Mercurial > hg > truffle
diff graal/com.oracle.max.criutils/src/com/oracle/max/criutils/CompilationPrinter.java @ 3733:e233f5660da4
Added Java files from Maxine project.
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Sat, 17 Dec 2011 19:59:18 +0100 |
parents | |
children | bc8527f3071c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.criutils/src/com/oracle/max/criutils/CompilationPrinter.java Sat Dec 17 19:59:18 2011 +0100 @@ -0,0 +1,244 @@ +/* + * 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.criutils; + +import java.io.*; + +import com.sun.cri.ci.*; +import com.sun.cri.ci.CiAddress.Scale; +import com.sun.cri.ci.CiValue.Formatter; +import com.sun.cri.ri.*; + +/** + * Utility for printing compilation related data structures at various compilation phases. + * The output format is such that it can then be fed to the + * <a href="https://c1visualizer.dev.java.net/">C1 Visualizer</a>. + */ +public class CompilationPrinter { + public static final String COLUMN_END = " <|@"; + public static final String HOVER_START = "<@"; + public static final String HOVER_SEP = "|@"; + public static final String HOVER_END = ">@"; + + private static OutputStream globalOut; + + /** + * Gets a global output stream on a file in the current working directory. + * This stream is first opened if necessary. The name of the file + * is {@code "compilations-" + System.currentTimeMillis() + ".cfg"}. + * + * @return the global output stream or {@code null} if there was an error opening the file for writing + */ + public static synchronized OutputStream globalOut() { + if (globalOut == null) { + File file = new File("compilations-" + System.currentTimeMillis() + ".cfg"); + try { + globalOut = new FileOutputStream(file); + } catch (FileNotFoundException e) { + TTY.println("WARNING: Could not open " + file.getAbsolutePath()); + } + } + return globalOut; + } + + protected final LogStream out; + + /** + * Creates a control flow graph printer. + * + * @param os where the output generated via this printer will be sent + */ + public CompilationPrinter(OutputStream os) { + out = new LogStream(os); + } + + /** + * Flushes all buffered output to the underlying output stream. + */ + public void flush() { + out.flush(); + } + + protected void begin(String string) { + out.println("begin_" + string); + out.adjustIndentation(2); + } + + protected void end(String string) { + out.adjustIndentation(-2); + out.println("end_" + string); + } + + /** + * Prints a compilation timestamp for a given method. + * + * @param method the method for which a timestamp will be printed + */ + public void printCompilation(RiMethod method) { + begin("compilation"); + out.print("name \" ").print(CiUtil.format("%H::%n", method, true)).println('"'); + out.print("method \"").print(CiUtil.format("%f %r %H.%n(%p)", method, true)).println('"'); + out.print("date ").println(System.currentTimeMillis()); + end("compilation"); + } + + /** + * Formats a given {@linkplain FrameState JVM frame state} as a multi line string. + */ + protected String debugInfoToString(CiCodePos codePos, CiBitMap registerRefMap, CiBitMap frameRefMap, OperandFormatter fmt, CiArchitecture arch) { + StringBuilder sb = new StringBuilder(); + + if (registerRefMap != null) { + sb.append("reg-ref-map:"); + for (int reg = registerRefMap.nextSetBit(0); reg >= 0; reg = registerRefMap.nextSetBit(reg + 1)) { + sb.append(' ').append(arch == null ? "reg" + reg : arch.registers[reg]); + } + sb.append("\n"); + } + + if (frameRefMap != null) { + sb.append("frame-ref-map:"); + for (int reg = frameRefMap.nextSetBit(0); reg >= 0; reg = frameRefMap.nextSetBit(reg + 1)) { + sb.append(' ').append(CiStackSlot.get(CiKind.Object, reg)); + } + sb.append("\n"); + } + + if (codePos != null) { + do { + sb.append(CiUtil.toLocation(codePos.method, codePos.bci)); + sb.append('\n'); + if (codePos instanceof CiFrame) { + CiFrame frame = (CiFrame) codePos; + if (frame.numStack > 0) { + sb.append("stack: "); + for (int i = 0; i < frame.numStack; i++) { + sb.append(valueToString(frame.getStackValue(i), fmt)).append(' '); + } + sb.append("\n"); + } + + if (frame.numLocks > 0) { + sb.append("locks: "); + for (int i = 0; i < frame.numLocks; ++i) { + sb.append(valueToString(frame.getLockValue(i), fmt)).append(' '); + } + sb.append("\n"); + } + + sb.append("locals: "); + for (int i = 0; i < frame.numLocals; i++) { + sb.append(valueToString(frame.getLocalValue(i), fmt)).append(' '); + } + sb.append("\n"); + } + codePos = codePos.caller; + } while (codePos != null); + } + return sb.toString(); + } + + + protected String valueToString(CiValue value, Formatter operandFmt) { + if (value == null) { + return "-"; + } + return operandFmt.format(value); + } + + + /** + * Formats LIR operands as expected by the C1 Visualizer. + */ + public static class OperandFormatter extends Formatter { + /** + * The textual delimiters used for an operand depend on the context in which it is being + * printed. When printed as part of a frame state or as the result operand in a HIR node listing, + * it is enclosed in double-quotes (i.e. {@code "}'s). + */ + public final boolean asStateOrHIROperandResult; + + public OperandFormatter(boolean asStateOrHIROperandResult) { + this.asStateOrHIROperandResult = asStateOrHIROperandResult; + } + + @Override + public String format(CiValue operand) { + if (operand.isLegal()) { + String op; + if (operand.isVariableOrRegister() || operand.isStackSlot()) { + op = operand.name(); + } else if (operand.isConstant()) { + CiConstant constant = (CiConstant) operand; + op = operand.kind.javaName + ":" + operand.kind.format(constant.boxedValue()); + } else if (operand.isAddress()) { + CiAddress address = (CiAddress) operand; + op = "Base:" + format(address.base); + if (!address.index.isIllegal()) { + op += " Index:" + format(address.index); + } + if (address.scale != Scale.Times1) { + op += " * " + address.scale.value; + } + op += " Disp:" + address.displacement; + } else { + assert operand.isIllegal(); + op = "-"; + } + if (operand.kind != CiKind.Illegal) { + op += "|" + operand.kind.typeChar; + } + if (asStateOrHIROperandResult) { + op = " \"" + op.replace('"', '\'') + "\" "; + } + return op; + } + return ""; + } + } + + public void printMachineCode(String code, String label) { + if (code.length() == 0) { + return; + } + if (label != null) { + begin("cfg"); + out.print("name \"").print(label).println('"'); + end("cfg"); + } + begin("nmethod"); + out.print(code); + out.println(" <|@"); + end("nmethod"); + } + + public void printBytecodes(String code) { + if (code.length() == 0) { + return; + } + begin("bytecodes"); + out.print(code); + out.println(" <|@"); + end("bytecodes"); + } +}