Mercurial > hg > truffle
changeset 4200:816ac0e579fb
Move printer into separate project.
line wrap: on
line diff
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalContext.java Tue Jan 03 16:29:28 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalContext.java Tue Jan 03 16:44:31 2012 +0100 @@ -23,7 +23,6 @@ package com.oracle.max.graal.compiler; import com.oracle.max.criutils.*; -import com.oracle.max.graal.compiler.debug.*; import com.oracle.max.graal.compiler.observer.*; /** @@ -32,7 +31,7 @@ */ public class GraalContext { - public static final GraalContext EMPTY_CONTEXT = new GraalContext(true, "silent context"); + public static final GraalContext EMPTY_CONTEXT = new GraalContext("silent context"); public final ObservableContext observable = new ObservableContext(); public final GraalTimers timers = new GraalTimers(); @@ -40,35 +39,16 @@ private final String name; - private GraalContext(boolean empty, String name) { + public GraalContext(String name) { this.name = name; - if (!empty) { - reset(); - } - } - - public GraalContext(String name) { - this(false, name); } public boolean isObserved() { return observable.isObserved(); } - public void reset() { - observable.clear(); - if (GraalOptions.PrintCFGToFile) { - observable.addCompilationObserver(new CFGPrinterObserver()); - } - if (GraalOptions.PrintIdealGraphLevel != 0 || GraalOptions.Plot || GraalOptions.PlotOnError) { - CompilationObserver observer; - if (GraalOptions.PrintIdealGraphFile) { - observer = new IdealGraphPrinterObserver(); - } else { - observer = new IdealGraphPrinterObserver(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort); - } - observable.addCompilationObserver(observer); - } + public void addCompilationObserver(CompilationObserver observer) { + observable.addCompilationObserver(observer); } public void print() {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/BasicIdealGraphPrinter.java Tue Jan 03 16:29:28 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,303 +0,0 @@ -/* - * 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.max.graal.compiler.debug; - -import java.io.*; -import java.util.*; -import java.util.Map.Entry; - -/** - * Elementary, generic generator of Ideal Graph Visualizer input for use in printers for specific data structures. - */ -public class BasicIdealGraphPrinter { - - /** - * Edge between two nodes. - */ - public static class Edge { - final String from; - final int fromIndex; - final String to; - final int toIndex; - final String label; - - public Edge(String from, int fromIndex, String to, int toIndex, String label) { - assert (from != null && to != null); - this.from = from; - this.fromIndex = fromIndex; - this.to = to; - this.toIndex = toIndex; - this.label = label; - } - - @Override - public int hashCode() { - int h = from.hashCode() ^ to.hashCode(); - 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.equals(other.from) - && fromIndex == other.fromIndex - && to.equals(other.to) - && toIndex == other.toIndex - && (label == other.label || (label != null && label.equals(other.label))); - } - return false; - } - } - - private final PrintStream stream; - - /** - * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream. - */ - public BasicIdealGraphPrinter(OutputStream stream) { - this.stream = new PrintStream(stream); - } - - /** - * Flushes any buffered output. - */ - public void flush() { - stream.flush(); - } - - /** - * Starts a new graph document. - */ - public void begin() { - stream.println("<graphDocument>"); - } - - public void beginGroup() { - stream.println("<group>"); - } - - public void beginMethod(String name, String shortName, int bci) { - stream.printf(" <method name='%s' shortName='%s' bci='%d'>%n", escape(name), escape(shortName), bci); - } - - public void beginBytecodes() { - stream.println(" <bytecodes>\n<![CDATA["); - } - - public void printBytecode(int bci, String mnemonic, int[] extra) { - stream.print(bci); - stream.print(' '); - stream.print(mnemonic); - if (extra != null) { - for (int b : extra) { - stream.print(' '); - stream.print(b); - } - } - stream.println(); - } - - public void endBytecodes() { - stream.println(" ]]></bytecodes>"); - } - - public void endMethod() { - stream.println(" </method>"); - } - - public void beginGraph(String title) { - stream.printf(" <graph name='%s'>%n", escape(title)); - } - - public void beginProperties() { - stream.print("<properties>"); - } - - public void printProperty(String name, String value) { - stream.printf("<p name='%s'>%s</p>", escape(name), escape(value)); - } - - public void endProperties() { - stream.print("</properties>"); - } - - public void printProperties(Map<String, String> properties) { - beginProperties(); - for (Entry<String, String> entry : properties.entrySet()) { - printProperty(entry.getKey(), entry.getValue()); - } - endProperties(); - } - - public void beginNodes() { - stream.println(" <nodes>"); - } - - public void beginNode(String id) { - stream.printf(" <node id='%s'>", escape(id)); - } - - public void endNode() { - stream.println(" </node>"); - } - - public void printNode(String id, Map<String, String> properties) { - beginNode(id); - if (properties != null) { - printProperties(properties); - } - endNode(); - } - - public void endNodes() { - stream.println(" </nodes>"); - } - - public void beginEdges() { - stream.println(" <edges>"); - } - - public void printEdge(Edge edge) { - stream.printf(" <edge from='%s' fromIndex='%d' to='%s' toIndex='%d' label='%s' />%n", escape(edge.from), edge.fromIndex, escape(edge.to), edge.toIndex, escape(edge.label)); - } - - public void endEdges() { - stream.println(" </edges>"); - } - - public void beginControlFlow() { - stream.println(" <controlFlow>"); - } - - public void beginBlock(String name) { - stream.printf(" <block name='%s'>%n", escape(name)); - } - - public void beginSuccessors() { - stream.println(" <successors>"); - } - - public void printSuccessor(String name) { - stream.printf(" <successor name='%s'/>%n", escape(name)); - } - - public void endSuccessors() { - stream.println(" </successors>"); - } - - public void beginBlockNodes() { - stream.println(" <nodes>"); - } - - public void printBlockNode(String nodeId) { - stream.printf(" <node id='%s'/>%n", escape(nodeId)); - } - - public void endBlockNodes() { - stream.println(" </nodes>"); - } - - public void endBlock() { - stream.println(" </block>"); - } - - public void endControlFlow() { - stream.println(" </controlFlow>"); - } - - public void endGraph() { - stream.println(" </graph>"); - } - - /** - * Ends the current group. - */ - public void endGroup() { - stream.println("</group>"); - } - - /** - * Finishes the graph document and flushes the output stream. - */ - public void end() { - stream.println("</graphDocument>"); - flush(); - } - - private static String escape(String s) { - StringBuilder str = null; - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - switch (c) { - case '&': - case '<': - case '>': - case '"': - case '\'': - if (str == null) { - str = new StringBuilder(); - str.append(s, 0, i); - } - switch(c) { - case '&': - str.append("&"); - break; - case '<': - str.append("<"); - break; - case '>': - str.append(">"); - break; - case '"': - str.append("""); - break; - case '\'': - str.append("'"); - break; - default: - assert false; - } - break; - default: - if (str != null) { - str.append(c); - } - break; - } - } - if (str == null) { - return s; - } else { - return str.toString(); - } - } -}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinter.java Tue Jan 03 16:29:28 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,480 +0,0 @@ -/* - * Copyright (c) 2009, 2012, 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.max.graal.compiler.debug; - -import static com.oracle.max.cri.ci.CiValueUtil.*; - -import java.io.*; -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.alloc.*; -import com.oracle.max.graal.compiler.alloc.Interval.UsePosList; -import com.oracle.max.graal.compiler.graphbuilder.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.schedule.*; -import com.oracle.max.graal.graph.*; -import com.oracle.max.graal.graph.Node.*; -import com.oracle.max.graal.graph.NodeClass.*; -import com.oracle.max.graal.nodes.*; -import com.oracle.max.graal.nodes.calc.*; - -/** - * Utility for printing Graal IR at various compilation phases. - */ -public class CFGPrinter extends CompilationPrinter { - - public final ByteArrayOutputStream buffer; - public final GraalCompilation compilation; - public final CiTarget target; - public final RiRuntime runtime; - - /** - * Creates a control flow graph printer. - * - * @param buffer where the output generated via this printer shown be written - */ - public CFGPrinter(ByteArrayOutputStream buffer, GraalCompilation compilation) { - super(buffer); - this.buffer = buffer; - this.compilation = compilation; - this.target = compilation.compiler.target; - this.runtime = compilation.compiler.runtime; - } - - public CFGPrinter(ByteArrayOutputStream buffer, GraalCompilation compilation, CiTarget target, RiRuntime runtime) { - super(buffer); - this.buffer = buffer; - this.compilation = compilation; - this.target = target; - this.runtime = runtime; - } - - /** - * Prints the control flow graph denoted by a given block map. - * - * @param label A label describing the compilation phase that produced the control flow graph. - * @param blockMap A data structure describing the blocks in a method and how they are connected. - */ - public void printCFG(String label, BlockMap blockMap) { - begin("cfg"); - out.print("name \"").print(label).println('"'); - for (BlockMap.Block block : blockMap.blocks) { - begin("block"); - printBlock(block); - end("block"); - } - end("cfg"); - } - - private void printBlock(BlockMap.Block block) { - out.print("name \"B").print(block.startBci).println('"'); - out.print("from_bci ").println(block.startBci); - out.print("to_bci ").println(block.endBci); - - out.println("predecessors "); - - out.print("successors "); - for (BlockMap.Block succ : block.successors) { - if (!succ.isExceptionEntry) { - out.print("\"B").print(succ.startBci).print("\" "); - } - } - out.println(); - - out.print("xhandlers"); - for (BlockMap.Block succ : block.successors) { - if (succ.isExceptionEntry) { - out.print("\"B").print(succ.startBci).print("\" "); - } - } - out.println(); - - out.print("flags "); - if (block.isExceptionEntry) { - out.print("\"ex\" "); - } - if (block.isLoopHeader) { - out.print("\"plh\" "); - } - out.println(); - - out.print("loop_depth ").println(Long.bitCount(block.loops)); - } - - - /** - * Prints the specified list of blocks. - * - * @param label A label describing the compilation phase that produced the control flow graph. - * @param blocks The list of blocks to be printed. - * @param printNodes If {@code true} the nodes in the block will be printed. - */ - public void printCFG(String label, List<? extends Block> blocks, boolean printNodes) { - begin("cfg"); - out.print("name \"").print(label).println('"'); - for (Block block : blocks) { - printBlock(block, printNodes); - } - end("cfg"); - } - - private void printBlock(Block block, boolean printNodes) { - begin("block"); - - out.print("name \"").print(blockToString(block)).println('"'); - out.println("from_bci -1"); - out.println("to_bci -1"); - - out.print("predecessors "); - for (Block pred : block.getPredecessors()) { - out.print("\"").print(blockToString(pred)).print("\" "); - } - out.println(); - - out.print("successors "); - for (Block succ : block.getSuccessors()) { - if (!succ.isExceptionBlock()) { - out.print("\"").print(blockToString(succ)).print("\" "); - } - } - out.println(); - - out.print("xhandlers"); - for (Block succ : block.getSuccessors()) { - if (succ.isExceptionBlock()) { - out.print("\"").print(blockToString(succ)).print("\" "); - } - } - out.println(); - - out.print("flags "); - if (block.isLoopHeader()) { - out.print("\"llh\" "); - } - if (block.isLoopEnd()) { - out.print("\"lle\" "); - } - if (block.isExceptionBlock()) { - out.print("\"ex\" "); - } - out.println(); - - out.print("loop_index ").println(block.loopIndex()); - out.print("loop_depth ").println(block.loopDepth()); - - if (printNodes) { - printNodes(block); - } - - if (block instanceof LIRBlock) { - printLIR((LIRBlock) block); - } - - end("block"); - } - - private void printNodes(Block block) { - begin("IR"); - out.println("HIR"); - out.disableIndentation(); - - if (block.getPredecessors().size() == 0) { - // Currently method parameters are not in the schedule, so print them separately here. - for (ValueNode param : block.firstNode().graph().getNodes(LocalNode.class)) { - printNode(param); - } - } - if (block.firstNode() instanceof MergeNode) { - // Currently phi functions are not in the schedule, so print them separately here. - for (ValueNode phi : ((MergeNode) block.firstNode()).phis()) { - printNode(phi); - } - } - - for (Node node : block.getInstructions()) { - printNode(node); - } - out.enableIndentation(); - end("IR"); - } - - private void printNode(Node node) { - if (node instanceof FixedWithNextNode) { - out.print("f ").print(HOVER_START).print("#").print(HOVER_SEP).print("fixed with next").print(HOVER_END).println(COLUMN_END); - } else if (node instanceof FixedNode) { - out.print("f ").print(HOVER_START).print("*").print(HOVER_SEP).print("fixed").print(HOVER_END).println(COLUMN_END); - } else if (node instanceof FloatingNode) { - out.print("f ").print(HOVER_START).print("~").print(HOVER_SEP).print("floating").print(HOVER_END).println(COLUMN_END); - } - if (compilation.nodeOperands != null && node instanceof ValueNode) { - CiValue operand = compilation.operand((ValueNode) node); - if (operand != null) { - out.print("result ").print(operand.toString()).println(COLUMN_END); - } - } - out.print("tid ").print(nodeToString(node)).println(COLUMN_END); - - if (node instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) node; - if (stateSplit.stateAfter() != null) { - String state = stateToString(stateSplit.stateAfter()); - out.print("st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).println(COLUMN_END); - } - } - - Map<Object, Object> props = new TreeMap<>(node.getDebugProperties()); - out.print("d ").print(HOVER_START).print("d").print(HOVER_SEP); - out.println("=== Debug Properties ==="); - for (Map.Entry<Object, Object> entry : props.entrySet()) { - out.print(entry.getKey().toString()).print(": ").print(entry.getValue() == null ? "[null]" : entry.getValue().toString()).println(); - } - out.println("=== Inputs ==="); - printNamedNodes(node, node.inputs().iterator(), "", "\n", null); - out.println("=== Succesors ==="); - printNamedNodes(node, node.successors().iterator(), "", "\n", null); - out.println("=== Usages ==="); - if (!node.usages().isEmpty()) { - for (Node usage : node.usages()) { - out.print(nodeToString(usage)).print(" "); - } - out.println(); - } - out.println("=== Predecessor ==="); - out.print(nodeToString(node.predecessor())).print(" "); - out.print(HOVER_END).println(COLUMN_END); - - out.print("instruction "); - out.print(HOVER_START).print(node.getNodeClass().shortName()).print(HOVER_SEP).print(node.getClass().getName()).print(HOVER_END).print(" "); - printNamedNodes(node, node.inputs().iterator(), "", "", "#NDF"); - printNamedNodes(node, node.successors().iterator(), "#", "", "#NDF"); - for (Map.Entry<Object, Object> entry : props.entrySet()) { - String key = entry.getKey().toString(); - if (key.startsWith("data.") && !key.equals("data.stamp")) { - out.print(key.substring("data.".length())).print(": ").print(entry.getValue() == null ? "[null]" : entry.getValue().toString()).print(" "); - } - } - out.print(COLUMN_END).print(' ').println(COLUMN_END); - } - - private void printNamedNodes(Node node, NodeClassIterator iter, String prefix, String suffix, String hideSuffix) { - int lastIndex = -1; - while (iter.hasNext()) { - Position pos = iter.nextPosition(); - if (hideSuffix != null && node.getNodeClass().getName(pos).endsWith(hideSuffix)) { - continue; - } - - if (pos.index != lastIndex) { - if (lastIndex != -1) { - out.print(suffix); - } - out.print(prefix).print(node.getNodeClass().getName(pos)).print(": "); - lastIndex = pos.index; - } - out.print(nodeToString(node.getNodeClass().get(node, pos))).print(" "); - } - if (lastIndex != -1) { - out.print(suffix); - } - } - - private String stateToString(FrameState state) { - StringBuilder buf = new StringBuilder(); - FrameState curState = state; - do { - buf.append(CiUtil.toLocation(curState.method(), curState.bci)).append('\n'); - - if (curState.stackSize() > 0) { - buf.append("stack: "); - for (int i = 0; i < curState.stackSize(); i++) { - buf.append(stateValueToString(curState.stackAt(i))).append(' '); - } - buf.append("\n"); - } - - if (curState.locksSize() > 0) { - buf.append("locks: "); - for (int i = 0; i < curState.locksSize(); ++i) { - buf.append(stateValueToString(curState.lockAt(i))).append(' '); - } - buf.append("\n"); - } - - buf.append("locals: "); - for (int i = 0; i < curState.localsSize(); i++) { - buf.append(stateValueToString(curState.localAt(i))).append(' '); - } - buf.append("\n"); - - curState = curState.outerFrameState(); - } while (curState != null); - - return buf.toString(); - } - - private String stateValueToString(ValueNode value) { - String result = nodeToString(value); - if (value != null) { - CiValue operand = compilation.operand(value); - if (operand != null) { - result += ": " + operand; - } - } - return result; - } - - /** - * Prints the LIR for each instruction in a given block. - * - * @param block the block to print - */ - private void printLIR(LIRBlock block) { - List<LIRInstruction> lir = block.lir(); - if (lir == null) { - return; - } - - begin("IR"); - out.println("LIR"); - - if (block.phis != null) { - CiValue[] results = block.phis.results(); - for (int i = 0; i < results.length; i++) { - out.print("instruction PHI ").print(results[i].toString()).print(" = ("); - String sep = ""; - for (LIRBlock pred : block.getLIRPredecessors()) { - out.print(sep).print(block.phis.inputs(pred)[i].toString()); - sep = ", "; - } - out.print(")").print(COLUMN_END).println(COLUMN_END); - } - } - - for (int i = 0; i < lir.size(); i++) { - LIRInstruction inst = lir.get(i); - out.printf("nr %4d ", inst.id()).print(COLUMN_END); - - if (inst.info != null) { - int level = out.indentationLevel(); - out.adjustIndentation(-level); - String state; - if (inst.info.hasDebugInfo()) { - state = debugInfoToString(inst.info.debugInfo().codePos, inst.info.debugInfo().registerRefMap, inst.info.debugInfo().frameRefMap, target.arch); - } else { - state = debugInfoToString(inst.info.topFrame, null, null, target.arch); - } - if (state != null) { - out.print(" st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).print(COLUMN_END); - } - out.adjustIndentation(level); - } - - out.print(" instruction ").print(inst.toString()).print(COLUMN_END); - out.println(COLUMN_END); - } - end("IR"); - } - - private String nodeToString(Node node) { - if (node == null) { - return "-"; - } - String prefix; - if (node instanceof BeginNode && compilation != null && compilation.lir() == null) { - prefix = "B"; - } else if (node instanceof ValueNode) { - ValueNode value = (ValueNode) node; - if (value.kind() == CiKind.Illegal) { - prefix = "v"; - } else { - prefix = String.valueOf(value.kind().typeChar); - } - } else { - prefix = "?"; - } - return prefix + node.toString(Verbosity.Id); - } - - private String blockToString(Block block) { - if (compilation != null && compilation.lir() == null) { - // During all the front-end phases, the block schedule is built only for the debug output. - // Therefore, the block numbers would be different for every CFG printed -> use the id of the first instruction. - return "B" + block.firstNode().toString(Verbosity.Id); - } else { - // LIR instructions contain references to blocks and these blocks are printed as the blockID -> use the blockID. - return "B" + block.blockID(); - } - } - - - public void printIntervals(String label, Interval[] intervals) { - begin("intervals"); - out.println(String.format("name \"%s\"", label)); - - for (Interval interval : intervals) { - if (interval != null) { - printInterval(interval); - } - } - - end("intervals"); - } - - private void printInterval(Interval interval) { - out.printf("%s %s ", interval.operand, (isRegister(interval.operand) ? "fixed" : interval.kind().name())); - if (isRegister(interval.operand)) { - out.printf("\"[%s|%c]\"", interval.operand, interval.operand.kind.typeChar); - } else { - if (interval.location() != null) { - out.printf("\"[%s|%c]\"", interval.location(), interval.location().kind.typeChar); - } - } - - Interval hint = interval.locationHint(false); - out.printf("%s %s ", interval.splitParent().operand, hint != null ? hint.operand : -1); - - // print ranges - Range cur = interval.first(); - while (cur != Range.EndMarker) { - out.printf("[%d, %d[", cur.from, cur.to); - cur = cur.next; - assert cur != null : "range list not closed with range sentinel"; - } - - // print use positions - int prev = 0; - UsePosList usePosList = interval.usePosList(); - for (int i = usePosList.size() - 1; i >= 0; --i) { - assert prev < usePosList.usePos(i) : "use positions not sorted"; - out.printf("%d %s ", usePosList.usePos(i), usePosList.registerPriority(i)); - prev = usePosList.usePos(i); - } - - out.printf(" \"%s\"", interval.spillState()); - out.println(); - } -}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinterObserver.java Tue Jan 03 16:29:28 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,138 +0,0 @@ -/* - * 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.max.graal.compiler.debug; - -import java.io.*; -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.alloc.*; -import com.oracle.max.graal.compiler.graphbuilder.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.observer.*; -import com.oracle.max.graal.compiler.schedule.*; -import com.oracle.max.graal.graph.*; -import com.oracle.max.graal.nodes.*; - -/** - * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the <a - * href="http://java.net/projects/c1visualizer/">C1 Visualizer</a>. - */ -public class CFGPrinterObserver implements CompilationObserver { - - /** - * A thread local stack of {@link CFGPrinter}s to support thread-safety and re-entrant compilation. - */ - private ThreadLocal<LinkedList<CFGPrinter>> observations = new ThreadLocal<LinkedList<CFGPrinter>>() { - @Override - protected java.util.LinkedList<CFGPrinter> initialValue() { - return new LinkedList<>(); - } - }; - - @Override - public void compilationStarted(GraalCompilation compilation) { - if (TTY.isSuppressed()) { - return; - } - - CFGPrinter cfgPrinter = new CFGPrinter(new ByteArrayOutputStream(), compilation); - cfgPrinter.printCompilation(compilation.method); - observations.get().push(cfgPrinter); - } - - @Override - public void compilationEvent(CompilationEvent event) { - if (TTY.isSuppressed()) { - return; - } - CFGPrinter cfgPrinter = observations.get().peek(); - if (cfgPrinter == null) { - return; - } - - RiRuntime runtime = cfgPrinter.runtime; - BlockMap blockMap = event.debugObject(BlockMap.class); - Graph graph = event.debugObject(Graph.class); - IdentifyBlocksPhase schedule = event.debugObject(IdentifyBlocksPhase.class); - LIR lir = event.debugObject(LIR.class); - LinearScan allocator = event.debugObject(LinearScan.class); - Interval[] intervals = event.debugObject(Interval[].class); - CiTargetMethod targetMethod = event.debugObject(CiTargetMethod.class); - - if (blockMap != null) { - cfgPrinter.printCFG(event.label, blockMap); - cfgPrinter.printBytecodes(runtime.disassemble(blockMap.method)); - } - if (lir != null) { - cfgPrinter.printCFG(event.label, lir.codeEmittingOrder(), graph != null); - if (targetMethod != null) { - cfgPrinter.printMachineCode(runtime.disassemble(targetMethod), null); - } - } else if (graph != null) { - List<? extends Block> blocks = null; - if (schedule == null) { - try { - schedule = new IdentifyBlocksPhase(true, LIRBlock.FACTORY); - schedule.apply((StructuredGraph) graph, false); - blocks = schedule.getBlocks(); - - ComputeLinearScanOrder clso = new ComputeLinearScanOrder(schedule.getBlocks().size(), schedule.loopCount(), (LIRBlock) schedule.getStartBlock()); - blocks = clso.codeEmittingOrder(); - } catch (Throwable t) { - // nothing to do here... - } - } - if (blocks != null) { - cfgPrinter.printCFG(event.label, blocks, true); - } - } - if (allocator != null && intervals != null) { - cfgPrinter.printIntervals(event.label, intervals); - } - } - - @Override - public void compilationFinished(GraalCompilation compilation) { - if (TTY.isSuppressed()) { - return; - } - CFGPrinter cfgPrinter = observations.get().pop(); - cfgPrinter.flush(); - - OutputStream stream = CompilationPrinter.globalOut(); - if (stream != null) { - synchronized (stream) { - try { - stream.write(cfgPrinter.buffer.toByteArray()); - stream.flush(); - } catch (IOException e) { - TTY.println("WARNING: Error writing CFGPrinter output: %s", e); - } - } - } - } -}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java Tue Jan 03 16:29:28 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,419 +0,0 @@ -/* - * 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.max.graal.compiler.debug; - -import java.io.*; -import java.util.*; -import java.util.Map.Entry; - -import com.oracle.max.cri.ri.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.debug.BasicIdealGraphPrinter.Edge; -import com.oracle.max.graal.compiler.graphbuilder.*; -import com.oracle.max.graal.compiler.schedule.*; -import com.oracle.max.graal.compiler.util.*; -import com.oracle.max.graal.compiler.util.LoopUtil.Loop; -import com.oracle.max.graal.graph.*; -import com.oracle.max.graal.graph.Node.Verbosity; -import com.oracle.max.graal.graph.NodeClass.NodeClassIterator; -import com.oracle.max.graal.graph.NodeClass.Position; -import com.oracle.max.graal.nodes.*; -import com.oracle.max.graal.nodes.loop.*; - -/** - * Generates a representation of {@link Graph Graphs} that can be visualized and inspected with the <a - * href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>. - */ -public class IdealGraphPrinter { - - private final BasicIdealGraphPrinter printer; - private final HashSet<Class<?>> omittedClasses = new HashSet<>(); - private final Set<Node> noBlockNodes = new HashSet<>(); - - /** - * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream. - */ - public IdealGraphPrinter(OutputStream stream) { - this.printer = new BasicIdealGraphPrinter(stream); - } - - /** - * Adds a node class that is omitted in the output. - */ - public void addOmittedClass(Class<?> clazz) { - omittedClasses.add(clazz); - } - - /** - * Flushes any buffered output. - */ - public void flush() { - printer.flush(); - } - - /** - * Starts a new graph document. - */ - public void begin() { - printer.begin(); - } - - /** - * Starts a new group of graphs with the given name, short name and method byte code index (BCI) as properties. - */ - public void beginGroup(String name, String shortName, RiResolvedMethod method, int bci, String origin) { - printer.beginGroup(); - printer.beginProperties(); - printer.printProperty("name", name); - printer.printProperty("origin", origin); - printer.endProperties(); - printer.beginMethod(name, shortName, bci); - if (GraalOptions.PrintIdealGraphBytecodes && method != null) { - printer.beginBytecodes(); - BytecodeStream bytecodes = new BytecodeStream(method.code()); - while (bytecodes.currentBC() != Bytecodes.END) { - int startBCI = bytecodes.currentBCI(); - String mnemonic = Bytecodes.nameOf(bytecodes.currentBC()); - int[] extra = null; - if (bytecodes.nextBCI() > startBCI + 1) { - extra = new int[bytecodes.nextBCI() - (startBCI + 1)]; - for (int i = 0; i < extra.length; i++) { - extra[i] = bytecodes.readUByte(startBCI + 1 + i); - } - } - printer.printBytecode(startBCI, mnemonic, extra); - bytecodes.next(); - } - printer.endBytecodes(); - } - printer.endMethod(); - } - - /** - * Ends the current group. - */ - public void endGroup() { - printer.endGroup(); - } - - /** - * Finishes the graph document and flushes the output stream. - */ - public void end() { - printer.end(); - } - - public void print(Graph graph, String title, boolean shortNames) { - print(graph, title, shortNames, null); - } - - /** - * Prints an entire {@link Graph} with the specified title, optionally using short names for nodes. - */ - public void print(Graph graph, String title, boolean shortNames, IdentifyBlocksPhase predefinedSchedule) { - printer.beginGraph(title); - noBlockNodes.clear(); - IdentifyBlocksPhase schedule = predefinedSchedule; - if (schedule == null) { - try { - schedule = new IdentifyBlocksPhase(true); - schedule.apply((StructuredGraph) graph, false); - } catch (Throwable t) { - // nothing to do here... - } - } - List<Loop> loops = null; - try { - loops = LoopUtil.computeLoops((StructuredGraph) graph); - // loop.nodes() does some more calculations which may fail, so execute this here as well (result is cached) - if (loops != null) { - for (Loop loop : loops) { - loop.nodes(); - } - } - } catch (Throwable t) { - t.printStackTrace(); - loops = null; - } - - printer.beginNodes(); - List<Edge> edges = printNodes(graph, shortNames, schedule == null ? null : schedule.getNodeToBlock(), loops); - printer.endNodes(); - - printer.beginEdges(); - for (Edge edge : edges) { - printer.printEdge(edge); - } - printer.endEdges(); - - if (schedule != null) { - printer.beginControlFlow(); - for (Block block : schedule.getBlocks()) { - printBlock(graph, block, schedule.getNodeToBlock()); - } - printNoBlock(); - printer.endControlFlow(); - } - - printer.endGraph(); - flush(); - } - - private List<Edge> printNodes(Graph graph, boolean shortNames, NodeMap<Block> nodeToBlock, List<Loop> loops) { - ArrayList<Edge> edges = new ArrayList<>(); - NodeBitMap loopExits = graph.createNodeBitMap(); - if (loops != null) { - for (Loop loop : loops) { - loopExits.setUnion(loop.exits()); - } - } - - NodeMap<Set<Entry<String, Integer>>> colors = graph.createNodeMap(); - NodeMap<Set<Entry<String, String>>> colorsToString = graph.createNodeMap(); - NodeMap<Set<String>> bits = graph.createNodeMap(); -// TODO This code was never reachable, since there was no code putting a NodeMap or NodeBitMap into the debugObjects. -// If you need to reactivate this code, put the mapping from names to values into a helper object and register it in the new debugObjects array. -// -// if (debugObjects != null) { -// for (Entry<String, Object> entry : debugObjects.entrySet()) { -// String name = entry.getKey(); -// Object obj = entry.getValue(); -// if (obj instanceof NodeMap) { -// Map<Object, Integer> colorNumbers = new HashMap<Object, Integer>(); -// int nextColor = 0; -// NodeMap<?> map = (NodeMap<?>) obj; -// for (Entry<Node, ?> mapEntry : map.entries()) { -// Node node = mapEntry.getKey(); -// Object color = mapEntry.getValue(); -// Integer colorNumber = colorNumbers.get(color); -// if (colorNumber == null) { -// colorNumber = nextColor++; -// colorNumbers.put(color, colorNumber); -// } -// Set<Entry<String, Integer>> nodeColors = colors.get(node); -// if (nodeColors == null) { -// nodeColors = new HashSet<Entry<String, Integer>>(); -// colors.put(node, nodeColors); -// } -// nodeColors.add(new SimpleImmutableEntry<String, Integer>(name + "Color", colorNumber)); -// Set<Entry<String, String>> nodeColorStrings = colorsToString.get(node); -// if (nodeColorStrings == null) { -// nodeColorStrings = new HashSet<Entry<String, String>>(); -// colorsToString.put(node, nodeColorStrings); -// } -// nodeColorStrings.add(new SimpleImmutableEntry<String, String>(name, color.toString())); -// } -// } else if (obj instanceof NodeBitMap) { -// NodeBitMap bitmap = (NodeBitMap) obj; -// for (Node node : bitmap) { -// Set<String> nodeBits = bits.get(node); -// if (nodeBits == null) { -// nodeBits = new HashSet<String>(); -// bits.put(node, nodeBits); -// } -// nodeBits.add(name); -// } -// } -// } -// } - - for (Node node : graph.getNodes()) { - if (omittedClasses.contains(node.getClass())) { - continue; - } - - printer.beginNode(node.toString(Verbosity.Id)); - printer.beginProperties(); - printer.printProperty("idx", node.toString(Verbosity.Id)); - - Map<Object, Object> props = node.getDebugProperties(); - if (!props.containsKey("name") || props.get("name").toString().trim().length() == 0) { - String name; - if (shortNames) { - name = node.toString(Verbosity.Name); - } else { - name = node.toString(); - } - printer.printProperty("name", name); - } - printer.printProperty("class", node.getClass().getSimpleName()); - Block block = nodeToBlock == null ? null : nodeToBlock.get(node); - if (block != null) { - printer.printProperty("block", Integer.toString(block.blockID())); - if (!(node instanceof PhiNode || node instanceof FrameState || node instanceof LocalNode || node instanceof InductionVariableNode) && !block.getInstructions().contains(node)) { - printer.printProperty("notInOwnBlock", "true"); - } - } else { - printer.printProperty("block", "noBlock"); - noBlockNodes.add(node); - } - if (loopExits.isMarked(node)) { - printer.printProperty("loopExit", "true"); - } - StringBuilder sb = new StringBuilder(); - if (loops != null) { - for (Loop loop : loops) { - if (loop.nodes().isMarked(node)) { - if (sb.length() > 0) { - sb.append(", "); - } - sb.append(loop.loopBegin().toString(Verbosity.Id)); - } - } - } - if (sb.length() > 0) { - printer.printProperty("loops", sb.toString()); - } - - Set<Entry<String, Integer>> nodeColors = colors.get(node); - if (nodeColors != null) { - for (Entry<String, Integer> color : nodeColors) { - String name = color.getKey(); - Integer value = color.getValue(); - printer.printProperty(name, Integer.toString(value)); - } - } - Set<Entry<String, String>> nodeColorStrings = colorsToString.get(node); - if (nodeColorStrings != null) { - for (Entry<String, String> color : nodeColorStrings) { - String name = color.getKey(); - String value = color.getValue(); - printer.printProperty(name, value); - } - } - Set<String> nodeBits = bits.get(node); - if (nodeBits != null) { - for (String bit : nodeBits) { - printer.printProperty(bit, "true"); - } - } - - for (Entry<Object, Object> entry : props.entrySet()) { - String key = entry.getKey().toString(); - String value = entry.getValue() == null ? "null" : entry.getValue().toString(); - printer.printProperty(key, value); - } - - printer.endProperties(); - printer.endNode(); - - // successors - int fromIndex = 0; - NodeClassIterator succIter = node.successors().iterator(); - while (succIter.hasNext()) { - Position position = succIter.nextPosition(); - Node successor = node.getNodeClass().get(node, position); - if (successor != null && !omittedClasses.contains(successor.getClass())) { - edges.add(new Edge(node.toString(Verbosity.Id), fromIndex, successor.toString(Verbosity.Id), 0, node.getNodeClass().getName(position))); - } - fromIndex++; - } - - // inputs - int toIndex = 1; - NodeClassIterator inputIter = node.inputs().iterator(); - while (inputIter.hasNext()) { - Position position = inputIter.nextPosition(); - Node input = node.getNodeClass().get(node, position); - if (input != null && !omittedClasses.contains(input.getClass())) { - edges.add(new Edge(input.toString(Verbosity.Id), input.successors().explicitCount(), node.toString(Verbosity.Id), toIndex, node.getNodeClass().getName(position))); - } - toIndex++; - } - } - - return edges; - } - - private void printBlock(Graph graph, Block block, NodeMap<Block> nodeToBlock) { - printer.beginBlock(Integer.toString(block.blockID())); - printer.beginSuccessors(); - for (Block sux : block.getSuccessors()) { - if (sux != null) { - printer.printSuccessor(Integer.toString(sux.blockID())); - } - } - printer.endSuccessors(); - printer.beginBlockNodes(); - - Set<Node> nodes = new HashSet<>(block.getInstructions()); - - if (nodeToBlock != null) { - for (Node n : graph.getNodes()) { - Block blk = nodeToBlock.get(n); - if (blk == block) { - nodes.add(n); - } - } - } - - if (nodes.size() > 0) { - // if this is the first block: add all locals to this block - if (block.getInstructions().size() > 0 && block.getInstructions().get(0) == ((StructuredGraph) graph).start()) { - for (Node node : graph.getNodes()) { - if (node instanceof LocalNode) { - nodes.add(node); - } - } - } - - // add all framestates and phis to their blocks - for (Node node : block.getInstructions()) { - if (node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) { - nodes.add(((StateSplit) node).stateAfter()); - } - if (node instanceof MergeNode) { - for (PhiNode phi : ((MergeNode) node).phis()) { - nodes.add(phi); - } - if (node instanceof LoopBeginNode) { - for (InductionVariableNode iv : ((LoopBeginNode) node).inductionVariables()) { - nodes.add(iv); - } - } - } - } - - for (Node node : nodes) { - if (!omittedClasses.contains(node.getClass())) { - printer.printBlockNode(node.toString(Verbosity.Id)); - } - } - } - printer.endBlockNodes(); - printer.endBlock(); - } - - private void printNoBlock() { - if (!noBlockNodes.isEmpty()) { - printer.beginBlock("noBlock"); - printer.beginBlockNodes(); - for (Node node : noBlockNodes) { - printer.printBlockNode(node.toString(Verbosity.Id)); - } - printer.endBlockNodes(); - printer.endBlock(); - } - } - -}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java Tue Jan 03 16:29:28 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,265 +0,0 @@ -/* - * 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.max.graal.compiler.debug; - -import java.io.*; -import java.net.*; -import java.util.regex.*; - -import com.oracle.max.cri.ri.*; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.observer.*; -import com.oracle.max.graal.compiler.schedule.*; -import com.oracle.max.graal.graph.*; - -/** - * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation that can be - * inspected with the <a href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>. - */ -public class IdealGraphPrinterObserver implements CompilationObserver { - - private static final Pattern INVALID_CHAR = Pattern.compile("[^A-Za-z0-9_.-]"); - - private final String host; - private final int port; - - private static class PrintingContext { - public IdealGraphPrinter printer; - private OutputStream stream; - private Socket socket; - - } - private final ThreadLocal<PrintingContext> context = new ThreadLocal<PrintingContext>() { - @Override - protected PrintingContext initialValue() { - return new PrintingContext(); - } - }; - - /** - * Creates a new {@link IdealGraphPrinterObserver} that writes output to a file named after the compiled method. - */ - public IdealGraphPrinterObserver() { - this(null, -1); - } - - /** - * Creates a new {@link IdealGraphPrinterObserver} that sends output to a remote IdealGraphVisualizer instance. - */ - public IdealGraphPrinterObserver(String host, int port) { - this.host = host; - this.port = port; - } - - private PrintingContext context() { - return context.get(); - } - - private IdealGraphPrinter printer() { - return context().printer; - } - - private Socket socket() { - return context().socket; - } - - @Override - public void compilationStarted(GraalCompilation compilation) { - openPrinter(compilation, false); - } - - private void openPrinter(GraalCompilation compilation, boolean error) { - assert (context().stream == null && printer() == null); - if ((!TTY.isSuppressed() && GraalOptions.Plot) || (GraalOptions.PlotOnError && error)) { - String name; - if (compilation != null) { - name = compilation.method.holder().name(); - name = name.substring(1, name.length() - 1).replace('/', '.'); - name = name + "." + compilation.method.name(); - } else { - name = "null"; - } - - openPrinter(name, compilation == null ? null : compilation.method); - } - } - - private void openPrinter(String title, RiResolvedMethod method) { - assert (context().stream == null && printer() == null); - if (!TTY.isSuppressed()) { - // Use a filter to suppress a recursive attempt to open a printer - TTY.Filter filter = new TTY.Filter(); - try { - if (host != null) { - openNetworkPrinter(title, method); - } else { - openFilePrinter(title, method); - } - } finally { - filter.remove(); - } - } - } - - private void openFilePrinter(String title, RiResolvedMethod method) { - String filename = title + ".igv.xml"; - filename = INVALID_CHAR.matcher(filename).replaceAll("_"); - - try { - context().stream = new FileOutputStream(filename); - context().printer = new IdealGraphPrinter(context().stream); - printer().begin(); - printer().beginGroup(title, title, method, -1, "Graal"); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public boolean networkAvailable() { - try { - Socket s = new Socket(host, port); - s.setSoTimeout(10); - s.close(); - return true; - } catch (IOException e) { - return false; - } - } - - private void openNetworkPrinter(String title, RiResolvedMethod method) { - try { - context().socket = new Socket(host, port); - if (socket().getInputStream().read() == 'y') { - context().stream = new BufferedOutputStream(socket().getOutputStream(), 0x4000); - } else { - // server currently does not accept any input - socket().close(); - context().socket = null; - return; - } - - context().printer = new IdealGraphPrinter(context().stream); - printer().begin(); - printer().beginGroup(title, title, method, -1, "Graal"); - printer().flush(); - if (socket().getInputStream().read() != 'y') { - // server declines input for this method - socket().close(); - context().socket = null; - context().stream = null; - context().printer = null; - } - } catch (IOException e) { - System.err.println("Error opening connection to " + host + ":" + port + ": " + e); - - if (socket() != null) { - try { - socket().close(); - } catch (IOException ioe) { - } - context().socket = null; - } - context().stream = null; - context().printer = null; - } - } - - @Override - public void compilationEvent(CompilationEvent event) { - boolean lazyStart = false; - if (printer() == null && event.hasDebugObject(CompilationEvent.ERROR)) { - openPrinter(event.debugObject(GraalCompilation.class), true); - lazyStart = true; - } - Graph graph = event.debugObject(Graph.class); - if (printer() != null && graph != null) { - printer().print(graph, event.label, true, event.debugObject(IdentifyBlocksPhase.class)); - } - if (lazyStart && printer() != null) { - closePrinter(); - } - } - - @Override - public void compilationFinished(GraalCompilation compilation) { - if (printer() != null) { - closePrinter(); - } - } - - private void closePrinter() { - assert (printer() != null); - - try { - printer().endGroup(); - printer().end(); - - if (socket() != null) { - socket().close(); // also closes stream - } else { - context().stream.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - context().printer = null; - context().stream = null; - context().socket = null; - } - } - - public void printGraphs(String groupTitle, Graph... graphs) { - openPrinter(groupTitle, null); - if (printer() != null) { - int i = 0; - for (Graph graph : graphs) { - printer().print(graph, "Graph " + i, true); - i++; - } - closePrinter(); - } - } - - public void compilationStarted(String groupTitle) { - openPrinter(groupTitle, null); - } - - public void printGraph(String graphTitle, Graph graph) { - if (printer() != null) { - printer().print(graph, graphTitle, true); - } - } - - public void printSingleGraph(String title, Graph graph) { - printSingleGraph(title, title, graph); - } - - public void printSingleGraph(String groupTitle, String graphTitle, Graph graph) { - openPrinter(groupTitle, null); - if (printer() != null) { - printer().print(graph, graphTitle, true); - closePrinter(); - } - } -}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/InstructionPrinter.java Tue Jan 03 16:29:28 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2009, 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.max.graal.compiler.debug; - -import static com.oracle.max.graal.compiler.debug.InstructionPrinter.InstructionLineColumn.*; - -import com.oracle.max.criutils.*; -import com.oracle.max.graal.nodes.*; - -/** - * A {@link ValueVisitor} for {@linkplain #printInstruction(ValueNode) printing} - * an {@link FixedWithNextNode} as an expression or statement. - */ -public class InstructionPrinter { - - - /** - * The columns printed in a tabulated instruction - * {@linkplain InstructionPrinter#printInstructionListing(ValueNode) listing}. - */ - public enum InstructionLineColumn { - /** - * The instruction's bytecode index. - */ - BCI(2, "bci"), - - /** - * The instruction's use count. - */ - USE(7, "use"), - - /** - * The instruction as a {@linkplain com.oracle.max.graal.compiler.util.Util#valueString(com.oracle.max.graal.compiler.ir.Value) value}. - */ - VALUE(12, "tid"), - - /** - * The instruction formatted as an expression or statement. - */ - INSTRUCTION(19, "instr"), - - END(60, ""); - - final int position; - final String label; - - private InstructionLineColumn(int position, String label) { - this.position = position; - this.label = label; - } - - /** - * Prints this column's label to a given stream after padding the stream with '_' characters - * until its {@linkplain LogStream#position() position} is equal to this column's position. - * @param out the print stream - */ - public void printLabel(LogStream out) { - out.fillTo(position + out.indentationLevel(), '_'); - out.print(label); - } - - /** - * Prints space characters to a given stream until its {@linkplain LogStream#position() position} - * is equal to this column's position. - * @param out the print stream - */ - public void advance(LogStream out) { - out.fillTo(position + out.indentationLevel(), ' '); - } - } - - private final LogStream out; - - public InstructionPrinter(LogStream out) { - this.out = out; - } - - public LogStream out() { - return out; - } - - /** - * Prints a header for the tabulated data printed by {@link #printInstructionListing(ValueNode)}. - */ - public void printInstructionListingHeader() { - BCI.printLabel(out); - USE.printLabel(out); - VALUE.printLabel(out); - INSTRUCTION.printLabel(out); - END.printLabel(out); - out.println(); - } - - /** - * Prints an instruction listing on one line. The instruction listing is composed of the - * columns specified by {@link InstructionLineColumn}. - * - * @param instruction the instruction to print - */ - public void printInstructionListing(ValueNode instruction) { - int indentation = out.indentationLevel(); - out.fillTo(BCI.position + indentation, ' '). - print(0). - fillTo(USE.position + indentation, ' '). - print("0"). - fillTo(VALUE.position + indentation, ' '). - print(ValueUtil.valueString(instruction)). - fillTo(INSTRUCTION.position + indentation, ' '); - printInstruction(instruction); - if (instruction instanceof StateSplit) { - out.print(" [state: " + ((StateSplit) instruction).stateAfter() + "]"); - } - out.println(); - } - - public void printInstruction(ValueNode node) { - out.print(node.toString()); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/InstructionPrinter.java Tue Jan 03 16:44:31 2012 +0100 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2009, 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.max.graal.compiler.gen; + +import static com.oracle.max.graal.compiler.gen.InstructionPrinter.InstructionLineColumn.*; + +import com.oracle.max.criutils.*; +import com.oracle.max.graal.nodes.*; + +/** + * A {@link ValueVisitor} for {@linkplain #printInstruction(ValueNode) printing} + * an {@link FixedWithNextNode} as an expression or statement. + */ +public class InstructionPrinter { + + + /** + * The columns printed in a tabulated instruction + * {@linkplain InstructionPrinter#printInstructionListing(ValueNode) listing}. + */ + public enum InstructionLineColumn { + /** + * The instruction's bytecode index. + */ + BCI(2, "bci"), + + /** + * The instruction's use count. + */ + USE(7, "use"), + + /** + * The instruction as a {@linkplain com.oracle.max.graal.compiler.util.Util#valueString(com.oracle.max.graal.compiler.ir.Value) value}. + */ + VALUE(12, "tid"), + + /** + * The instruction formatted as an expression or statement. + */ + INSTRUCTION(19, "instr"), + + END(60, ""); + + final int position; + final String label; + + private InstructionLineColumn(int position, String label) { + this.position = position; + this.label = label; + } + + /** + * Prints this column's label to a given stream after padding the stream with '_' characters + * until its {@linkplain LogStream#position() position} is equal to this column's position. + * @param out the print stream + */ + public void printLabel(LogStream out) { + out.fillTo(position + out.indentationLevel(), '_'); + out.print(label); + } + + /** + * Prints space characters to a given stream until its {@linkplain LogStream#position() position} + * is equal to this column's position. + * @param out the print stream + */ + public void advance(LogStream out) { + out.fillTo(position + out.indentationLevel(), ' '); + } + } + + private final LogStream out; + + public InstructionPrinter(LogStream out) { + this.out = out; + } + + public LogStream out() { + return out; + } + + /** + * Prints a header for the tabulated data printed by {@link #printInstructionListing(ValueNode)}. + */ + public void printInstructionListingHeader() { + BCI.printLabel(out); + USE.printLabel(out); + VALUE.printLabel(out); + INSTRUCTION.printLabel(out); + END.printLabel(out); + out.println(); + } + + /** + * Prints an instruction listing on one line. The instruction listing is composed of the + * columns specified by {@link InstructionLineColumn}. + * + * @param instruction the instruction to print + */ + public void printInstructionListing(ValueNode instruction) { + int indentation = out.indentationLevel(); + out.fillTo(BCI.position + indentation, ' '). + print(0). + fillTo(USE.position + indentation, ' '). + print("0"). + fillTo(VALUE.position + indentation, ' '). + print(ValueUtil.valueString(instruction)). + fillTo(INSTRUCTION.position + indentation, ' '); + printInstruction(instruction); + if (instruction instanceof StateSplit) { + out.print(" [state: " + ((StateSplit) instruction).stateAfter() + "]"); + } + out.println(); + } + + public void printInstruction(ValueNode node) { + out.print(node.toString()); + } +}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Tue Jan 03 16:29:28 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Tue Jan 03 16:44:31 2012 +0100 @@ -40,7 +40,6 @@ import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.alloc.*; import com.oracle.max.graal.compiler.alloc.OperandPool.VariableFlag; -import com.oracle.max.graal.compiler.debug.*; import com.oracle.max.graal.compiler.graphbuilder.*; import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.schedule.*;
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graphbuilder/BytecodeLookupSwitch.java Tue Jan 03 16:29:28 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graphbuilder/BytecodeLookupSwitch.java Tue Jan 03 16:44:31 2012 +0100 @@ -25,7 +25,7 @@ /** * A utility for processing {@link Bytecodes#LOOKUPSWITCH} bytecodes. */ -public class BytecodeLookupSwitch extends BytecodeSwitch { +class BytecodeLookupSwitch extends BytecodeSwitch { private static final int OFFSET_TO_NUMBER_PAIRS = 4; private static final int OFFSET_TO_FIRST_PAIR_MATCH = 8; private static final int OFFSET_TO_FIRST_PAIR_OFFSET = 12;
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/CompilerImpl.java Tue Jan 03 16:29:28 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/CompilerImpl.java Tue Jan 03 16:44:31 2012 +0100 @@ -30,10 +30,12 @@ import com.oracle.max.cri.ri.*; import com.oracle.max.cri.xir.*; import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.observer.*; import com.oracle.max.graal.cri.*; import com.oracle.max.graal.hotspot.logging.*; import com.oracle.max.graal.hotspot.ri.*; import com.oracle.max.graal.hotspot.server.*; +import com.oracle.max.graal.printer.*; /** * Singleton class holding the instance of the GraalCompiler. @@ -212,6 +214,18 @@ public HotSpotRuntime getRuntime() { if (runtime == null) { context = new GraalContext("Virtual Machine Compiler"); + if (GraalOptions.PrintCFGToFile) { + context.addCompilationObserver(new CFGPrinterObserver()); + } + if (GraalOptions.PrintIdealGraphLevel != 0 || GraalOptions.Plot || GraalOptions.PlotOnError) { + CompilationObserver observer; + if (GraalOptions.PrintIdealGraphFile) { + observer = new IdealGraphPrinterObserver(); + } else { + observer = new IdealGraphPrinterObserver(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort); + } + context.addCompilationObserver(observer); + } runtime = new HotSpotRuntime(context, config, this); } return runtime;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/BasicIdealGraphPrinter.java Tue Jan 03 16:44:31 2012 +0100 @@ -0,0 +1,303 @@ +/* + * 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.max.graal.printer; + +import java.io.*; +import java.util.*; +import java.util.Map.Entry; + +/** + * Elementary, generic generator of Ideal Graph Visualizer input for use in printers for specific data structures. + */ +public class BasicIdealGraphPrinter { + + /** + * Edge between two nodes. + */ + public static class Edge { + final String from; + final int fromIndex; + final String to; + final int toIndex; + final String label; + + public Edge(String from, int fromIndex, String to, int toIndex, String label) { + assert (from != null && to != null); + this.from = from; + this.fromIndex = fromIndex; + this.to = to; + this.toIndex = toIndex; + this.label = label; + } + + @Override + public int hashCode() { + int h = from.hashCode() ^ to.hashCode(); + 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.equals(other.from) + && fromIndex == other.fromIndex + && to.equals(other.to) + && toIndex == other.toIndex + && (label == other.label || (label != null && label.equals(other.label))); + } + return false; + } + } + + private final PrintStream stream; + + /** + * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream. + */ + public BasicIdealGraphPrinter(OutputStream stream) { + this.stream = new PrintStream(stream); + } + + /** + * Flushes any buffered output. + */ + public void flush() { + stream.flush(); + } + + /** + * Starts a new graph document. + */ + public void begin() { + stream.println("<graphDocument>"); + } + + public void beginGroup() { + stream.println("<group>"); + } + + public void beginMethod(String name, String shortName, int bci) { + stream.printf(" <method name='%s' shortName='%s' bci='%d'>%n", escape(name), escape(shortName), bci); + } + + public void beginBytecodes() { + stream.println(" <bytecodes>\n<![CDATA["); + } + + public void printBytecode(int bci, String mnemonic, int[] extra) { + stream.print(bci); + stream.print(' '); + stream.print(mnemonic); + if (extra != null) { + for (int b : extra) { + stream.print(' '); + stream.print(b); + } + } + stream.println(); + } + + public void endBytecodes() { + stream.println(" ]]></bytecodes>"); + } + + public void endMethod() { + stream.println(" </method>"); + } + + public void beginGraph(String title) { + stream.printf(" <graph name='%s'>%n", escape(title)); + } + + public void beginProperties() { + stream.print("<properties>"); + } + + public void printProperty(String name, String value) { + stream.printf("<p name='%s'>%s</p>", escape(name), escape(value)); + } + + public void endProperties() { + stream.print("</properties>"); + } + + public void printProperties(Map<String, String> properties) { + beginProperties(); + for (Entry<String, String> entry : properties.entrySet()) { + printProperty(entry.getKey(), entry.getValue()); + } + endProperties(); + } + + public void beginNodes() { + stream.println(" <nodes>"); + } + + public void beginNode(String id) { + stream.printf(" <node id='%s'>", escape(id)); + } + + public void endNode() { + stream.println(" </node>"); + } + + public void printNode(String id, Map<String, String> properties) { + beginNode(id); + if (properties != null) { + printProperties(properties); + } + endNode(); + } + + public void endNodes() { + stream.println(" </nodes>"); + } + + public void beginEdges() { + stream.println(" <edges>"); + } + + public void printEdge(Edge edge) { + stream.printf(" <edge from='%s' fromIndex='%d' to='%s' toIndex='%d' label='%s' />%n", escape(edge.from), edge.fromIndex, escape(edge.to), edge.toIndex, escape(edge.label)); + } + + public void endEdges() { + stream.println(" </edges>"); + } + + public void beginControlFlow() { + stream.println(" <controlFlow>"); + } + + public void beginBlock(String name) { + stream.printf(" <block name='%s'>%n", escape(name)); + } + + public void beginSuccessors() { + stream.println(" <successors>"); + } + + public void printSuccessor(String name) { + stream.printf(" <successor name='%s'/>%n", escape(name)); + } + + public void endSuccessors() { + stream.println(" </successors>"); + } + + public void beginBlockNodes() { + stream.println(" <nodes>"); + } + + public void printBlockNode(String nodeId) { + stream.printf(" <node id='%s'/>%n", escape(nodeId)); + } + + public void endBlockNodes() { + stream.println(" </nodes>"); + } + + public void endBlock() { + stream.println(" </block>"); + } + + public void endControlFlow() { + stream.println(" </controlFlow>"); + } + + public void endGraph() { + stream.println(" </graph>"); + } + + /** + * Ends the current group. + */ + public void endGroup() { + stream.println("</group>"); + } + + /** + * Finishes the graph document and flushes the output stream. + */ + public void end() { + stream.println("</graphDocument>"); + flush(); + } + + private static String escape(String s) { + StringBuilder str = null; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + switch (c) { + case '&': + case '<': + case '>': + case '"': + case '\'': + if (str == null) { + str = new StringBuilder(); + str.append(s, 0, i); + } + switch(c) { + case '&': + str.append("&"); + break; + case '<': + str.append("<"); + break; + case '>': + str.append(">"); + break; + case '"': + str.append("""); + break; + case '\'': + str.append("'"); + break; + default: + assert false; + } + break; + default: + if (str != null) { + str.append(c); + } + break; + } + } + if (str == null) { + return s; + } else { + return str.toString(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinter.java Tue Jan 03 16:44:31 2012 +0100 @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2009, 2012, 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.max.graal.printer; + +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.io.*; +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.criutils.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.alloc.*; +import com.oracle.max.graal.compiler.alloc.Interval.UsePosList; +import com.oracle.max.graal.compiler.graphbuilder.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.graph.Node.*; +import com.oracle.max.graal.graph.NodeClass.*; +import com.oracle.max.graal.nodes.*; +import com.oracle.max.graal.nodes.calc.*; + +/** + * Utility for printing Graal IR at various compilation phases. + */ +class CFGPrinter extends CompilationPrinter { + + public final ByteArrayOutputStream buffer; + public final GraalCompilation compilation; + public final CiTarget target; + public final RiRuntime runtime; + + /** + * Creates a control flow graph printer. + * + * @param buffer where the output generated via this printer shown be written + */ + public CFGPrinter(ByteArrayOutputStream buffer, GraalCompilation compilation) { + super(buffer); + this.buffer = buffer; + this.compilation = compilation; + this.target = compilation.compiler.target; + this.runtime = compilation.compiler.runtime; + } + + public CFGPrinter(ByteArrayOutputStream buffer, GraalCompilation compilation, CiTarget target, RiRuntime runtime) { + super(buffer); + this.buffer = buffer; + this.compilation = compilation; + this.target = target; + this.runtime = runtime; + } + + /** + * Prints the control flow graph denoted by a given block map. + * + * @param label A label describing the compilation phase that produced the control flow graph. + * @param blockMap A data structure describing the blocks in a method and how they are connected. + */ + public void printCFG(String label, BlockMap blockMap) { + begin("cfg"); + out.print("name \"").print(label).println('"'); + for (BlockMap.Block block : blockMap.blocks) { + begin("block"); + printBlock(block); + end("block"); + } + end("cfg"); + } + + private void printBlock(BlockMap.Block block) { + out.print("name \"B").print(block.startBci).println('"'); + out.print("from_bci ").println(block.startBci); + out.print("to_bci ").println(block.endBci); + + out.println("predecessors "); + + out.print("successors "); + for (BlockMap.Block succ : block.successors) { + if (!succ.isExceptionEntry) { + out.print("\"B").print(succ.startBci).print("\" "); + } + } + out.println(); + + out.print("xhandlers"); + for (BlockMap.Block succ : block.successors) { + if (succ.isExceptionEntry) { + out.print("\"B").print(succ.startBci).print("\" "); + } + } + out.println(); + + out.print("flags "); + if (block.isExceptionEntry) { + out.print("\"ex\" "); + } + if (block.isLoopHeader) { + out.print("\"plh\" "); + } + out.println(); + + out.print("loop_depth ").println(Long.bitCount(block.loops)); + } + + + /** + * Prints the specified list of blocks. + * + * @param label A label describing the compilation phase that produced the control flow graph. + * @param blocks The list of blocks to be printed. + * @param printNodes If {@code true} the nodes in the block will be printed. + */ + public void printCFG(String label, List<? extends Block> blocks, boolean printNodes) { + begin("cfg"); + out.print("name \"").print(label).println('"'); + for (Block block : blocks) { + printBlock(block, printNodes); + } + end("cfg"); + } + + private void printBlock(Block block, boolean printNodes) { + begin("block"); + + out.print("name \"").print(blockToString(block)).println('"'); + out.println("from_bci -1"); + out.println("to_bci -1"); + + out.print("predecessors "); + for (Block pred : block.getPredecessors()) { + out.print("\"").print(blockToString(pred)).print("\" "); + } + out.println(); + + out.print("successors "); + for (Block succ : block.getSuccessors()) { + if (!succ.isExceptionBlock()) { + out.print("\"").print(blockToString(succ)).print("\" "); + } + } + out.println(); + + out.print("xhandlers"); + for (Block succ : block.getSuccessors()) { + if (succ.isExceptionBlock()) { + out.print("\"").print(blockToString(succ)).print("\" "); + } + } + out.println(); + + out.print("flags "); + if (block.isLoopHeader()) { + out.print("\"llh\" "); + } + if (block.isLoopEnd()) { + out.print("\"lle\" "); + } + if (block.isExceptionBlock()) { + out.print("\"ex\" "); + } + out.println(); + + out.print("loop_index ").println(block.loopIndex()); + out.print("loop_depth ").println(block.loopDepth()); + + if (printNodes) { + printNodes(block); + } + + if (block instanceof LIRBlock) { + printLIR((LIRBlock) block); + } + + end("block"); + } + + private void printNodes(Block block) { + begin("IR"); + out.println("HIR"); + out.disableIndentation(); + + if (block.getPredecessors().size() == 0) { + // Currently method parameters are not in the schedule, so print them separately here. + for (ValueNode param : block.firstNode().graph().getNodes(LocalNode.class)) { + printNode(param); + } + } + if (block.firstNode() instanceof MergeNode) { + // Currently phi functions are not in the schedule, so print them separately here. + for (ValueNode phi : ((MergeNode) block.firstNode()).phis()) { + printNode(phi); + } + } + + for (Node node : block.getInstructions()) { + printNode(node); + } + out.enableIndentation(); + end("IR"); + } + + private void printNode(Node node) { + if (node instanceof FixedWithNextNode) { + out.print("f ").print(HOVER_START).print("#").print(HOVER_SEP).print("fixed with next").print(HOVER_END).println(COLUMN_END); + } else if (node instanceof FixedNode) { + out.print("f ").print(HOVER_START).print("*").print(HOVER_SEP).print("fixed").print(HOVER_END).println(COLUMN_END); + } else if (node instanceof FloatingNode) { + out.print("f ").print(HOVER_START).print("~").print(HOVER_SEP).print("floating").print(HOVER_END).println(COLUMN_END); + } + if (compilation.nodeOperands != null && node instanceof ValueNode) { + CiValue operand = compilation.operand((ValueNode) node); + if (operand != null) { + out.print("result ").print(operand.toString()).println(COLUMN_END); + } + } + out.print("tid ").print(nodeToString(node)).println(COLUMN_END); + + if (node instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) node; + if (stateSplit.stateAfter() != null) { + String state = stateToString(stateSplit.stateAfter()); + out.print("st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).println(COLUMN_END); + } + } + + Map<Object, Object> props = new TreeMap<>(node.getDebugProperties()); + out.print("d ").print(HOVER_START).print("d").print(HOVER_SEP); + out.println("=== Debug Properties ==="); + for (Map.Entry<Object, Object> entry : props.entrySet()) { + out.print(entry.getKey().toString()).print(": ").print(entry.getValue() == null ? "[null]" : entry.getValue().toString()).println(); + } + out.println("=== Inputs ==="); + printNamedNodes(node, node.inputs().iterator(), "", "\n", null); + out.println("=== Succesors ==="); + printNamedNodes(node, node.successors().iterator(), "", "\n", null); + out.println("=== Usages ==="); + if (!node.usages().isEmpty()) { + for (Node usage : node.usages()) { + out.print(nodeToString(usage)).print(" "); + } + out.println(); + } + out.println("=== Predecessor ==="); + out.print(nodeToString(node.predecessor())).print(" "); + out.print(HOVER_END).println(COLUMN_END); + + out.print("instruction "); + out.print(HOVER_START).print(node.getNodeClass().shortName()).print(HOVER_SEP).print(node.getClass().getName()).print(HOVER_END).print(" "); + printNamedNodes(node, node.inputs().iterator(), "", "", "#NDF"); + printNamedNodes(node, node.successors().iterator(), "#", "", "#NDF"); + for (Map.Entry<Object, Object> entry : props.entrySet()) { + String key = entry.getKey().toString(); + if (key.startsWith("data.") && !key.equals("data.stamp")) { + out.print(key.substring("data.".length())).print(": ").print(entry.getValue() == null ? "[null]" : entry.getValue().toString()).print(" "); + } + } + out.print(COLUMN_END).print(' ').println(COLUMN_END); + } + + private void printNamedNodes(Node node, NodeClassIterator iter, String prefix, String suffix, String hideSuffix) { + int lastIndex = -1; + while (iter.hasNext()) { + Position pos = iter.nextPosition(); + if (hideSuffix != null && node.getNodeClass().getName(pos).endsWith(hideSuffix)) { + continue; + } + + if (pos.index != lastIndex) { + if (lastIndex != -1) { + out.print(suffix); + } + out.print(prefix).print(node.getNodeClass().getName(pos)).print(": "); + lastIndex = pos.index; + } + out.print(nodeToString(node.getNodeClass().get(node, pos))).print(" "); + } + if (lastIndex != -1) { + out.print(suffix); + } + } + + private String stateToString(FrameState state) { + StringBuilder buf = new StringBuilder(); + FrameState curState = state; + do { + buf.append(CiUtil.toLocation(curState.method(), curState.bci)).append('\n'); + + if (curState.stackSize() > 0) { + buf.append("stack: "); + for (int i = 0; i < curState.stackSize(); i++) { + buf.append(stateValueToString(curState.stackAt(i))).append(' '); + } + buf.append("\n"); + } + + if (curState.locksSize() > 0) { + buf.append("locks: "); + for (int i = 0; i < curState.locksSize(); ++i) { + buf.append(stateValueToString(curState.lockAt(i))).append(' '); + } + buf.append("\n"); + } + + buf.append("locals: "); + for (int i = 0; i < curState.localsSize(); i++) { + buf.append(stateValueToString(curState.localAt(i))).append(' '); + } + buf.append("\n"); + + curState = curState.outerFrameState(); + } while (curState != null); + + return buf.toString(); + } + + private String stateValueToString(ValueNode value) { + String result = nodeToString(value); + if (value != null) { + CiValue operand = compilation.operand(value); + if (operand != null) { + result += ": " + operand; + } + } + return result; + } + + /** + * Prints the LIR for each instruction in a given block. + * + * @param block the block to print + */ + private void printLIR(LIRBlock block) { + List<LIRInstruction> lir = block.lir(); + if (lir == null) { + return; + } + + begin("IR"); + out.println("LIR"); + + if (block.phis != null) { + CiValue[] results = block.phis.results(); + for (int i = 0; i < results.length; i++) { + out.print("instruction PHI ").print(results[i].toString()).print(" = ("); + String sep = ""; + for (LIRBlock pred : block.getLIRPredecessors()) { + out.print(sep).print(block.phis.inputs(pred)[i].toString()); + sep = ", "; + } + out.print(")").print(COLUMN_END).println(COLUMN_END); + } + } + + for (int i = 0; i < lir.size(); i++) { + LIRInstruction inst = lir.get(i); + out.printf("nr %4d ", inst.id()).print(COLUMN_END); + + if (inst.info != null) { + int level = out.indentationLevel(); + out.adjustIndentation(-level); + String state; + if (inst.info.hasDebugInfo()) { + state = debugInfoToString(inst.info.debugInfo().codePos, inst.info.debugInfo().registerRefMap, inst.info.debugInfo().frameRefMap, target.arch); + } else { + state = debugInfoToString(inst.info.topFrame, null, null, target.arch); + } + if (state != null) { + out.print(" st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).print(COLUMN_END); + } + out.adjustIndentation(level); + } + + out.print(" instruction ").print(inst.toString()).print(COLUMN_END); + out.println(COLUMN_END); + } + end("IR"); + } + + private String nodeToString(Node node) { + if (node == null) { + return "-"; + } + String prefix; + if (node instanceof BeginNode && compilation != null && compilation.lir() == null) { + prefix = "B"; + } else if (node instanceof ValueNode) { + ValueNode value = (ValueNode) node; + if (value.kind() == CiKind.Illegal) { + prefix = "v"; + } else { + prefix = String.valueOf(value.kind().typeChar); + } + } else { + prefix = "?"; + } + return prefix + node.toString(Verbosity.Id); + } + + private String blockToString(Block block) { + if (compilation != null && compilation.lir() == null) { + // During all the front-end phases, the block schedule is built only for the debug output. + // Therefore, the block numbers would be different for every CFG printed -> use the id of the first instruction. + return "B" + block.firstNode().toString(Verbosity.Id); + } else { + // LIR instructions contain references to blocks and these blocks are printed as the blockID -> use the blockID. + return "B" + block.blockID(); + } + } + + + public void printIntervals(String label, Interval[] intervals) { + begin("intervals"); + out.println(String.format("name \"%s\"", label)); + + for (Interval interval : intervals) { + if (interval != null) { + printInterval(interval); + } + } + + end("intervals"); + } + + private void printInterval(Interval interval) { + out.printf("%s %s ", interval.operand, (isRegister(interval.operand) ? "fixed" : interval.kind().name())); + if (isRegister(interval.operand)) { + out.printf("\"[%s|%c]\"", interval.operand, interval.operand.kind.typeChar); + } else { + if (interval.location() != null) { + out.printf("\"[%s|%c]\"", interval.location(), interval.location().kind.typeChar); + } + } + + Interval hint = interval.locationHint(false); + out.printf("%s %s ", interval.splitParent().operand, hint != null ? hint.operand : -1); + + // print ranges + Range cur = interval.first(); + while (cur != Range.EndMarker) { + out.printf("[%d, %d[", cur.from, cur.to); + cur = cur.next; + assert cur != null : "range list not closed with range sentinel"; + } + + // print use positions + int prev = 0; + UsePosList usePosList = interval.usePosList(); + for (int i = usePosList.size() - 1; i >= 0; --i) { + assert prev < usePosList.usePos(i) : "use positions not sorted"; + out.printf("%d %s ", usePosList.usePos(i), usePosList.registerPriority(i)); + prev = usePosList.usePos(i); + } + + out.printf(" \"%s\"", interval.spillState()); + out.println(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinterObserver.java Tue Jan 03 16:44:31 2012 +0100 @@ -0,0 +1,138 @@ +/* + * 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.max.graal.printer; + +import java.io.*; +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.criutils.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.alloc.*; +import com.oracle.max.graal.compiler.graphbuilder.*; +import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.compiler.observer.*; +import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.nodes.*; + +/** + * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the <a + * href="http://java.net/projects/c1visualizer/">C1 Visualizer</a>. + */ +public class CFGPrinterObserver implements CompilationObserver { + + /** + * A thread local stack of {@link CFGPrinter}s to support thread-safety and re-entrant compilation. + */ + private ThreadLocal<LinkedList<CFGPrinter>> observations = new ThreadLocal<LinkedList<CFGPrinter>>() { + @Override + protected java.util.LinkedList<CFGPrinter> initialValue() { + return new LinkedList<>(); + } + }; + + @Override + public void compilationStarted(GraalCompilation compilation) { + if (TTY.isSuppressed()) { + return; + } + + CFGPrinter cfgPrinter = new CFGPrinter(new ByteArrayOutputStream(), compilation); + cfgPrinter.printCompilation(compilation.method); + observations.get().push(cfgPrinter); + } + + @Override + public void compilationEvent(CompilationEvent event) { + if (TTY.isSuppressed()) { + return; + } + CFGPrinter cfgPrinter = observations.get().peek(); + if (cfgPrinter == null) { + return; + } + + RiRuntime runtime = cfgPrinter.runtime; + BlockMap blockMap = event.debugObject(BlockMap.class); + Graph graph = event.debugObject(Graph.class); + IdentifyBlocksPhase schedule = event.debugObject(IdentifyBlocksPhase.class); + LIR lir = event.debugObject(LIR.class); + LinearScan allocator = event.debugObject(LinearScan.class); + Interval[] intervals = event.debugObject(Interval[].class); + CiTargetMethod targetMethod = event.debugObject(CiTargetMethod.class); + + if (blockMap != null) { + cfgPrinter.printCFG(event.label, blockMap); + cfgPrinter.printBytecodes(runtime.disassemble(blockMap.method)); + } + if (lir != null) { + cfgPrinter.printCFG(event.label, lir.codeEmittingOrder(), graph != null); + if (targetMethod != null) { + cfgPrinter.printMachineCode(runtime.disassemble(targetMethod), null); + } + } else if (graph != null) { + List<? extends Block> blocks = null; + if (schedule == null) { + try { + schedule = new IdentifyBlocksPhase(true, LIRBlock.FACTORY); + schedule.apply((StructuredGraph) graph, false); + blocks = schedule.getBlocks(); + + ComputeLinearScanOrder clso = new ComputeLinearScanOrder(schedule.getBlocks().size(), schedule.loopCount(), (LIRBlock) schedule.getStartBlock()); + blocks = clso.codeEmittingOrder(); + } catch (Throwable t) { + // nothing to do here... + } + } + if (blocks != null) { + cfgPrinter.printCFG(event.label, blocks, true); + } + } + if (allocator != null && intervals != null) { + cfgPrinter.printIntervals(event.label, intervals); + } + } + + @Override + public void compilationFinished(GraalCompilation compilation) { + if (TTY.isSuppressed()) { + return; + } + CFGPrinter cfgPrinter = observations.get().pop(); + cfgPrinter.flush(); + + OutputStream stream = CompilationPrinter.globalOut(); + if (stream != null) { + synchronized (stream) { + try { + stream.write(cfgPrinter.buffer.toByteArray()); + stream.flush(); + } catch (IOException e) { + TTY.println("WARNING: Error writing CFGPrinter output: %s", e); + } + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/IdealGraphPrinter.java Tue Jan 03 16:44:31 2012 +0100 @@ -0,0 +1,419 @@ +/* + * 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.max.graal.printer; + +import java.io.*; +import java.util.*; +import java.util.Map.Entry; + +import com.oracle.max.cri.ri.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.graphbuilder.*; +import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.compiler.util.LoopUtil.Loop; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.graph.Node.Verbosity; +import com.oracle.max.graal.graph.NodeClass.NodeClassIterator; +import com.oracle.max.graal.graph.NodeClass.Position; +import com.oracle.max.graal.nodes.*; +import com.oracle.max.graal.nodes.loop.*; +import com.oracle.max.graal.printer.BasicIdealGraphPrinter.*; + +/** + * Generates a representation of {@link Graph Graphs} that can be visualized and inspected with the <a + * href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>. + */ +class IdealGraphPrinter { + + private final BasicIdealGraphPrinter printer; + private final HashSet<Class<?>> omittedClasses = new HashSet<>(); + private final Set<Node> noBlockNodes = new HashSet<>(); + + /** + * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream. + */ + public IdealGraphPrinter(OutputStream stream) { + this.printer = new BasicIdealGraphPrinter(stream); + } + + /** + * Adds a node class that is omitted in the output. + */ + public void addOmittedClass(Class<?> clazz) { + omittedClasses.add(clazz); + } + + /** + * Flushes any buffered output. + */ + public void flush() { + printer.flush(); + } + + /** + * Starts a new graph document. + */ + public void begin() { + printer.begin(); + } + + /** + * Starts a new group of graphs with the given name, short name and method byte code index (BCI) as properties. + */ + public void beginGroup(String name, String shortName, RiResolvedMethod method, int bci, String origin) { + printer.beginGroup(); + printer.beginProperties(); + printer.printProperty("name", name); + printer.printProperty("origin", origin); + printer.endProperties(); + printer.beginMethod(name, shortName, bci); + if (GraalOptions.PrintIdealGraphBytecodes && method != null) { + printer.beginBytecodes(); + BytecodeStream bytecodes = new BytecodeStream(method.code()); + while (bytecodes.currentBC() != Bytecodes.END) { + int startBCI = bytecodes.currentBCI(); + String mnemonic = Bytecodes.nameOf(bytecodes.currentBC()); + int[] extra = null; + if (bytecodes.nextBCI() > startBCI + 1) { + extra = new int[bytecodes.nextBCI() - (startBCI + 1)]; + for (int i = 0; i < extra.length; i++) { + extra[i] = bytecodes.readUByte(startBCI + 1 + i); + } + } + printer.printBytecode(startBCI, mnemonic, extra); + bytecodes.next(); + } + printer.endBytecodes(); + } + printer.endMethod(); + } + + /** + * Ends the current group. + */ + public void endGroup() { + printer.endGroup(); + } + + /** + * Finishes the graph document and flushes the output stream. + */ + public void end() { + printer.end(); + } + + public void print(Graph graph, String title, boolean shortNames) { + print(graph, title, shortNames, null); + } + + /** + * Prints an entire {@link Graph} with the specified title, optionally using short names for nodes. + */ + public void print(Graph graph, String title, boolean shortNames, IdentifyBlocksPhase predefinedSchedule) { + printer.beginGraph(title); + noBlockNodes.clear(); + IdentifyBlocksPhase schedule = predefinedSchedule; + if (schedule == null) { + try { + schedule = new IdentifyBlocksPhase(true); + schedule.apply((StructuredGraph) graph, false); + } catch (Throwable t) { + // nothing to do here... + } + } + List<Loop> loops = null; + try { + loops = LoopUtil.computeLoops((StructuredGraph) graph); + // loop.nodes() does some more calculations which may fail, so execute this here as well (result is cached) + if (loops != null) { + for (Loop loop : loops) { + loop.nodes(); + } + } + } catch (Throwable t) { + t.printStackTrace(); + loops = null; + } + + printer.beginNodes(); + List<Edge> edges = printNodes(graph, shortNames, schedule == null ? null : schedule.getNodeToBlock(), loops); + printer.endNodes(); + + printer.beginEdges(); + for (Edge edge : edges) { + printer.printEdge(edge); + } + printer.endEdges(); + + if (schedule != null) { + printer.beginControlFlow(); + for (Block block : schedule.getBlocks()) { + printBlock(graph, block, schedule.getNodeToBlock()); + } + printNoBlock(); + printer.endControlFlow(); + } + + printer.endGraph(); + flush(); + } + + private List<Edge> printNodes(Graph graph, boolean shortNames, NodeMap<Block> nodeToBlock, List<Loop> loops) { + ArrayList<Edge> edges = new ArrayList<>(); + NodeBitMap loopExits = graph.createNodeBitMap(); + if (loops != null) { + for (Loop loop : loops) { + loopExits.setUnion(loop.exits()); + } + } + + NodeMap<Set<Entry<String, Integer>>> colors = graph.createNodeMap(); + NodeMap<Set<Entry<String, String>>> colorsToString = graph.createNodeMap(); + NodeMap<Set<String>> bits = graph.createNodeMap(); +// TODO This code was never reachable, since there was no code putting a NodeMap or NodeBitMap into the debugObjects. +// If you need to reactivate this code, put the mapping from names to values into a helper object and register it in the new debugObjects array. +// +// if (debugObjects != null) { +// for (Entry<String, Object> entry : debugObjects.entrySet()) { +// String name = entry.getKey(); +// Object obj = entry.getValue(); +// if (obj instanceof NodeMap) { +// Map<Object, Integer> colorNumbers = new HashMap<Object, Integer>(); +// int nextColor = 0; +// NodeMap<?> map = (NodeMap<?>) obj; +// for (Entry<Node, ?> mapEntry : map.entries()) { +// Node node = mapEntry.getKey(); +// Object color = mapEntry.getValue(); +// Integer colorNumber = colorNumbers.get(color); +// if (colorNumber == null) { +// colorNumber = nextColor++; +// colorNumbers.put(color, colorNumber); +// } +// Set<Entry<String, Integer>> nodeColors = colors.get(node); +// if (nodeColors == null) { +// nodeColors = new HashSet<Entry<String, Integer>>(); +// colors.put(node, nodeColors); +// } +// nodeColors.add(new SimpleImmutableEntry<String, Integer>(name + "Color", colorNumber)); +// Set<Entry<String, String>> nodeColorStrings = colorsToString.get(node); +// if (nodeColorStrings == null) { +// nodeColorStrings = new HashSet<Entry<String, String>>(); +// colorsToString.put(node, nodeColorStrings); +// } +// nodeColorStrings.add(new SimpleImmutableEntry<String, String>(name, color.toString())); +// } +// } else if (obj instanceof NodeBitMap) { +// NodeBitMap bitmap = (NodeBitMap) obj; +// for (Node node : bitmap) { +// Set<String> nodeBits = bits.get(node); +// if (nodeBits == null) { +// nodeBits = new HashSet<String>(); +// bits.put(node, nodeBits); +// } +// nodeBits.add(name); +// } +// } +// } +// } + + for (Node node : graph.getNodes()) { + if (omittedClasses.contains(node.getClass())) { + continue; + } + + printer.beginNode(node.toString(Verbosity.Id)); + printer.beginProperties(); + printer.printProperty("idx", node.toString(Verbosity.Id)); + + Map<Object, Object> props = node.getDebugProperties(); + if (!props.containsKey("name") || props.get("name").toString().trim().length() == 0) { + String name; + if (shortNames) { + name = node.toString(Verbosity.Name); + } else { + name = node.toString(); + } + printer.printProperty("name", name); + } + printer.printProperty("class", node.getClass().getSimpleName()); + Block block = nodeToBlock == null ? null : nodeToBlock.get(node); + if (block != null) { + printer.printProperty("block", Integer.toString(block.blockID())); + if (!(node instanceof PhiNode || node instanceof FrameState || node instanceof LocalNode || node instanceof InductionVariableNode) && !block.getInstructions().contains(node)) { + printer.printProperty("notInOwnBlock", "true"); + } + } else { + printer.printProperty("block", "noBlock"); + noBlockNodes.add(node); + } + if (loopExits.isMarked(node)) { + printer.printProperty("loopExit", "true"); + } + StringBuilder sb = new StringBuilder(); + if (loops != null) { + for (Loop loop : loops) { + if (loop.nodes().isMarked(node)) { + if (sb.length() > 0) { + sb.append(", "); + } + sb.append(loop.loopBegin().toString(Verbosity.Id)); + } + } + } + if (sb.length() > 0) { + printer.printProperty("loops", sb.toString()); + } + + Set<Entry<String, Integer>> nodeColors = colors.get(node); + if (nodeColors != null) { + for (Entry<String, Integer> color : nodeColors) { + String name = color.getKey(); + Integer value = color.getValue(); + printer.printProperty(name, Integer.toString(value)); + } + } + Set<Entry<String, String>> nodeColorStrings = colorsToString.get(node); + if (nodeColorStrings != null) { + for (Entry<String, String> color : nodeColorStrings) { + String name = color.getKey(); + String value = color.getValue(); + printer.printProperty(name, value); + } + } + Set<String> nodeBits = bits.get(node); + if (nodeBits != null) { + for (String bit : nodeBits) { + printer.printProperty(bit, "true"); + } + } + + for (Entry<Object, Object> entry : props.entrySet()) { + String key = entry.getKey().toString(); + String value = entry.getValue() == null ? "null" : entry.getValue().toString(); + printer.printProperty(key, value); + } + + printer.endProperties(); + printer.endNode(); + + // successors + int fromIndex = 0; + NodeClassIterator succIter = node.successors().iterator(); + while (succIter.hasNext()) { + Position position = succIter.nextPosition(); + Node successor = node.getNodeClass().get(node, position); + if (successor != null && !omittedClasses.contains(successor.getClass())) { + edges.add(new Edge(node.toString(Verbosity.Id), fromIndex, successor.toString(Verbosity.Id), 0, node.getNodeClass().getName(position))); + } + fromIndex++; + } + + // inputs + int toIndex = 1; + NodeClassIterator inputIter = node.inputs().iterator(); + while (inputIter.hasNext()) { + Position position = inputIter.nextPosition(); + Node input = node.getNodeClass().get(node, position); + if (input != null && !omittedClasses.contains(input.getClass())) { + edges.add(new Edge(input.toString(Verbosity.Id), input.successors().explicitCount(), node.toString(Verbosity.Id), toIndex, node.getNodeClass().getName(position))); + } + toIndex++; + } + } + + return edges; + } + + private void printBlock(Graph graph, Block block, NodeMap<Block> nodeToBlock) { + printer.beginBlock(Integer.toString(block.blockID())); + printer.beginSuccessors(); + for (Block sux : block.getSuccessors()) { + if (sux != null) { + printer.printSuccessor(Integer.toString(sux.blockID())); + } + } + printer.endSuccessors(); + printer.beginBlockNodes(); + + Set<Node> nodes = new HashSet<>(block.getInstructions()); + + if (nodeToBlock != null) { + for (Node n : graph.getNodes()) { + Block blk = nodeToBlock.get(n); + if (blk == block) { + nodes.add(n); + } + } + } + + if (nodes.size() > 0) { + // if this is the first block: add all locals to this block + if (block.getInstructions().size() > 0 && block.getInstructions().get(0) == ((StructuredGraph) graph).start()) { + for (Node node : graph.getNodes()) { + if (node instanceof LocalNode) { + nodes.add(node); + } + } + } + + // add all framestates and phis to their blocks + for (Node node : block.getInstructions()) { + if (node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) { + nodes.add(((StateSplit) node).stateAfter()); + } + if (node instanceof MergeNode) { + for (PhiNode phi : ((MergeNode) node).phis()) { + nodes.add(phi); + } + if (node instanceof LoopBeginNode) { + for (InductionVariableNode iv : ((LoopBeginNode) node).inductionVariables()) { + nodes.add(iv); + } + } + } + } + + for (Node node : nodes) { + if (!omittedClasses.contains(node.getClass())) { + printer.printBlockNode(node.toString(Verbosity.Id)); + } + } + } + printer.endBlockNodes(); + printer.endBlock(); + } + + private void printNoBlock() { + if (!noBlockNodes.isEmpty()) { + printer.beginBlock("noBlock"); + printer.beginBlockNodes(); + for (Node node : noBlockNodes) { + printer.printBlockNode(node.toString(Verbosity.Id)); + } + printer.endBlockNodes(); + printer.endBlock(); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/IdealGraphPrinterObserver.java Tue Jan 03 16:44:31 2012 +0100 @@ -0,0 +1,265 @@ +/* + * 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.max.graal.printer; + +import java.io.*; +import java.net.*; +import java.util.regex.*; + +import com.oracle.max.cri.ri.*; +import com.oracle.max.criutils.*; +import com.oracle.max.graal.compiler.*; +import com.oracle.max.graal.compiler.observer.*; +import com.oracle.max.graal.compiler.schedule.*; +import com.oracle.max.graal.graph.*; + +/** + * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation that can be + * inspected with the <a href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>. + */ +public class IdealGraphPrinterObserver implements CompilationObserver { + + private static final Pattern INVALID_CHAR = Pattern.compile("[^A-Za-z0-9_.-]"); + + private final String host; + private final int port; + + private static class PrintingContext { + public IdealGraphPrinter printer; + private OutputStream stream; + private Socket socket; + + } + private final ThreadLocal<PrintingContext> context = new ThreadLocal<PrintingContext>() { + @Override + protected PrintingContext initialValue() { + return new PrintingContext(); + } + }; + + /** + * Creates a new {@link IdealGraphPrinterObserver} that writes output to a file named after the compiled method. + */ + public IdealGraphPrinterObserver() { + this(null, -1); + } + + /** + * Creates a new {@link IdealGraphPrinterObserver} that sends output to a remote IdealGraphVisualizer instance. + */ + public IdealGraphPrinterObserver(String host, int port) { + this.host = host; + this.port = port; + } + + private PrintingContext context() { + return context.get(); + } + + private IdealGraphPrinter printer() { + return context().printer; + } + + private Socket socket() { + return context().socket; + } + + @Override + public void compilationStarted(GraalCompilation compilation) { + openPrinter(compilation, false); + } + + private void openPrinter(GraalCompilation compilation, boolean error) { + assert (context().stream == null && printer() == null); + if ((!TTY.isSuppressed() && GraalOptions.Plot) || (GraalOptions.PlotOnError && error)) { + String name; + if (compilation != null) { + name = compilation.method.holder().name(); + name = name.substring(1, name.length() - 1).replace('/', '.'); + name = name + "." + compilation.method.name(); + } else { + name = "null"; + } + + openPrinter(name, compilation == null ? null : compilation.method); + } + } + + private void openPrinter(String title, RiResolvedMethod method) { + assert (context().stream == null && printer() == null); + if (!TTY.isSuppressed()) { + // Use a filter to suppress a recursive attempt to open a printer + TTY.Filter filter = new TTY.Filter(); + try { + if (host != null) { + openNetworkPrinter(title, method); + } else { + openFilePrinter(title, method); + } + } finally { + filter.remove(); + } + } + } + + private void openFilePrinter(String title, RiResolvedMethod method) { + String filename = title + ".igv.xml"; + filename = INVALID_CHAR.matcher(filename).replaceAll("_"); + + try { + context().stream = new FileOutputStream(filename); + context().printer = new IdealGraphPrinter(context().stream); + printer().begin(); + printer().beginGroup(title, title, method, -1, "Graal"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public boolean networkAvailable() { + try { + Socket s = new Socket(host, port); + s.setSoTimeout(10); + s.close(); + return true; + } catch (IOException e) { + return false; + } + } + + private void openNetworkPrinter(String title, RiResolvedMethod method) { + try { + context().socket = new Socket(host, port); + if (socket().getInputStream().read() == 'y') { + context().stream = new BufferedOutputStream(socket().getOutputStream(), 0x4000); + } else { + // server currently does not accept any input + socket().close(); + context().socket = null; + return; + } + + context().printer = new IdealGraphPrinter(context().stream); + printer().begin(); + printer().beginGroup(title, title, method, -1, "Graal"); + printer().flush(); + if (socket().getInputStream().read() != 'y') { + // server declines input for this method + socket().close(); + context().socket = null; + context().stream = null; + context().printer = null; + } + } catch (IOException e) { + System.err.println("Error opening connection to " + host + ":" + port + ": " + e); + + if (socket() != null) { + try { + socket().close(); + } catch (IOException ioe) { + } + context().socket = null; + } + context().stream = null; + context().printer = null; + } + } + + @Override + public void compilationEvent(CompilationEvent event) { + boolean lazyStart = false; + if (printer() == null && event.hasDebugObject(CompilationEvent.ERROR)) { + openPrinter(event.debugObject(GraalCompilation.class), true); + lazyStart = true; + } + Graph graph = event.debugObject(Graph.class); + if (printer() != null && graph != null) { + printer().print(graph, event.label, true, event.debugObject(IdentifyBlocksPhase.class)); + } + if (lazyStart && printer() != null) { + closePrinter(); + } + } + + @Override + public void compilationFinished(GraalCompilation compilation) { + if (printer() != null) { + closePrinter(); + } + } + + private void closePrinter() { + assert (printer() != null); + + try { + printer().endGroup(); + printer().end(); + + if (socket() != null) { + socket().close(); // also closes stream + } else { + context().stream.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + context().printer = null; + context().stream = null; + context().socket = null; + } + } + + public void printGraphs(String groupTitle, Graph... graphs) { + openPrinter(groupTitle, null); + if (printer() != null) { + int i = 0; + for (Graph graph : graphs) { + printer().print(graph, "Graph " + i, true); + i++; + } + closePrinter(); + } + } + + public void compilationStarted(String groupTitle) { + openPrinter(groupTitle, null); + } + + public void printGraph(String graphTitle, Graph graph) { + if (printer() != null) { + printer().print(graph, graphTitle, true); + } + } + + public void printSingleGraph(String title, Graph graph) { + printSingleGraph(title, title, graph); + } + + public void printSingleGraph(String groupTitle, String graphTitle, Graph graph) { + openPrinter(groupTitle, null); + if (printer() != null) { + printer().print(graph, graphTitle, true); + closePrinter(); + } + } +}
--- a/graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/Snippets.java Tue Jan 03 16:29:28 2012 +0100 +++ b/graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/Snippets.java Tue Jan 03 16:44:31 2012 +0100 @@ -27,7 +27,6 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.debug.*; import com.oracle.max.graal.compiler.graphbuilder.*; import com.oracle.max.graal.compiler.observer.*; import com.oracle.max.graal.compiler.phases.*; @@ -37,6 +36,7 @@ import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.extended.*; import com.oracle.max.graal.nodes.java.*; +import com.oracle.max.graal.printer.*; /** * Utilities for snippet installation and management.
--- a/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/GraphTest.java Tue Jan 03 16:29:28 2012 +0100 +++ b/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/GraphTest.java Tue Jan 03 16:44:31 2012 +0100 @@ -30,10 +30,10 @@ import com.oracle.max.cri.ri.*; import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.debug.*; import com.oracle.max.graal.compiler.graphbuilder.*; import com.oracle.max.graal.cri.*; import com.oracle.max.graal.nodes.*; +import com.oracle.max.graal.printer.*; /** * Base class for Graal compiler unit tests. These are white box tests
--- a/mx/projects Tue Jan 03 16:29:28 2012 +0100 +++ b/mx/projects Tue Jan 03 16:44:31 2012 +0100 @@ -44,7 +44,7 @@ # graal.hotspot project@com.oracle.max.graal.hotspot@subDir=graal project@com.oracle.max.graal.hotspot@sourceDirs=src -project@com.oracle.max.graal.hotspot@dependencies=com.oracle.max.graal.snippets,com.oracle.max.asmdis +project@com.oracle.max.graal.hotspot@dependencies=com.oracle.max.graal.snippets,com.oracle.max.asmdis,com.oracle.max.graal.printer project@com.oracle.max.graal.hotspot@checkstyle=com.oracle.max.graal.graph # graal.graph @@ -55,7 +55,7 @@ # graal.snippets project@com.oracle.max.graal.snippets@subDir=graal project@com.oracle.max.graal.snippets@sourceDirs=src,test -project@com.oracle.max.graal.snippets@dependencies=com.oracle.max.graal.compiler +project@com.oracle.max.graal.snippets@dependencies=com.oracle.max.graal.printer,com.oracle.max.graal.compiler project@com.oracle.max.graal.snippets@checkstyle=com.oracle.max.graal.graph # graal.nodes @@ -70,10 +70,16 @@ project@com.oracle.max.graal.compiler@dependencies=com.oracle.max.asm,com.oracle.max.graal.nodes project@com.oracle.max.graal.compiler@checkstyle=com.oracle.max.graal.graph +# graal.printer +project@com.oracle.max.graal.printer@subDir=graal +project@com.oracle.max.graal.printer@sourceDirs=src +project@com.oracle.max.graal.printer@dependencies=com.oracle.max.graal.compiler,com.oracle.max.asm,com.oracle.max.graal.nodes +project@com.oracle.max.graal.printer@checkstyle=com.oracle.max.graal.graph + # graal.test project@com.oracle.max.graal.tests@subDir=graal project@com.oracle.max.graal.tests@sourceDirs=src -project@com.oracle.max.graal.tests@dependencies=com.oracle.max.graal.compiler +project@com.oracle.max.graal.tests@dependencies=com.oracle.max.graal.compiler,com.oracle.max.graal.printer project@com.oracle.max.graal.tests@checkstyle=com.oracle.max.graal.graph # max.asm