001/*
002 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.printer;
024
025import java.io.*;
026import java.util.*;
027
028import jdk.internal.jvmci.code.*;
029import jdk.internal.jvmci.meta.*;
030
031import com.oracle.graal.debug.*;
032import com.oracle.graal.lir.util.*;
033
034/**
035 * Utility for printing compilation related data structures at various compilation phases. The
036 * output format is such that it can then be fed to the <a
037 * href="https://c1visualizer.dev.java.net/">C1 Visualizer</a>.
038 */
039public class CompilationPrinter implements Closeable {
040
041    public static final String COLUMN_END = " <|@";
042    public static final String HOVER_START = "<@";
043    public static final String HOVER_SEP = "|@";
044    public static final String HOVER_END = ">@";
045
046    private static OutputStream globalOut;
047
048    /**
049     * Gets a global output stream on a file in the current working directory. This stream is first
050     * opened if necessary. The name of the file is
051     * {@code "compilations-" + System.currentTimeMillis() + ".cfg"}.
052     *
053     * @return the global output stream or {@code null} if there was an error opening the file for
054     *         writing
055     */
056    public static synchronized OutputStream globalOut() {
057        if (globalOut == null) {
058            File file = new File("compilations-" + System.currentTimeMillis() + ".cfg");
059            try {
060                globalOut = new FileOutputStream(file);
061            } catch (FileNotFoundException e) {
062                TTY.println("WARNING: Could not open " + file.getAbsolutePath());
063            }
064        }
065        return globalOut;
066    }
067
068    protected final LogStream out;
069
070    /**
071     * Creates a control flow graph printer.
072     *
073     * @param os where the output generated via this printer will be sent
074     */
075    public CompilationPrinter(OutputStream os) {
076        out = new LogStream(os);
077    }
078
079    /**
080     * Flushes all buffered output to the underlying output stream.
081     */
082    public void flush() {
083        out.flush();
084    }
085
086    @Override
087    public void close() {
088        out.out().close();
089    }
090
091    protected void begin(String string) {
092        out.println("begin_" + string);
093        out.adjustIndentation(2);
094    }
095
096    protected void end(String string) {
097        out.adjustIndentation(-2);
098        out.println("end_" + string);
099    }
100
101    /**
102     * Prints a compilation timestamp for a given method.
103     *
104     * @param method the method for which a timestamp will be printed
105     */
106    public void printCompilation(JavaMethod method) {
107        begin("compilation");
108        out.print("name \" ").print(method.format("%H::%n")).println('"');
109        out.print("method \"").print(method.format("%f %r %H.%n(%p)")).println('"');
110        out.print("date ").println(System.currentTimeMillis());
111        end("compilation");
112    }
113
114    /**
115     * Formats given debug info as a multi line string.
116     */
117    protected String debugInfoToString(BytecodePosition codePos, ReferenceMap refMap, IndexedValueMap liveBasePointers, RegisterSaveLayout calleeSaveInfo) {
118        StringBuilder sb = new StringBuilder();
119        if (refMap != null) {
120            sb.append("reference-map: ");
121            sb.append(refMap.toString());
122            sb.append("\n");
123        }
124        if (liveBasePointers != null) {
125            sb.append("live-base-pointers: ");
126            sb.append(liveBasePointers);
127            sb.append("\n");
128        }
129
130        if (calleeSaveInfo != null) {
131            sb.append("callee-save-info:");
132            for (Map.Entry<Register, Integer> e : calleeSaveInfo.registersToSlots(true).entrySet()) {
133                sb.append(" " + e.getKey() + " -> s" + e.getValue());
134            }
135            sb.append("\n");
136        }
137
138        if (codePos != null) {
139            BytecodePosition curCodePos = codePos;
140            List<VirtualObject> virtualObjects = new ArrayList<>();
141            do {
142                sb.append(MetaUtil.toLocation(curCodePos.getMethod(), curCodePos.getBCI()));
143                sb.append('\n');
144                if (curCodePos instanceof BytecodeFrame) {
145                    BytecodeFrame frame = (BytecodeFrame) curCodePos;
146                    if (frame.numStack > 0) {
147                        sb.append("stack: ");
148                        for (int i = 0; i < frame.numStack; i++) {
149                            sb.append(valueToString(frame.getStackValue(i), virtualObjects)).append(' ');
150                        }
151                        sb.append("\n");
152                    }
153                    sb.append("locals: ");
154                    for (int i = 0; i < frame.numLocals; i++) {
155                        sb.append(valueToString(frame.getLocalValue(i), virtualObjects)).append(' ');
156                    }
157                    sb.append("\n");
158                    if (frame.numLocks > 0) {
159                        sb.append("locks: ");
160                        for (int i = 0; i < frame.numLocks; ++i) {
161                            sb.append(valueToString(frame.getLockValue(i), virtualObjects)).append(' ');
162                        }
163                        sb.append("\n");
164                    }
165
166                }
167                curCodePos = curCodePos.getCaller();
168            } while (curCodePos != null);
169
170            for (int i = 0; i < virtualObjects.size(); i++) {
171                VirtualObject obj = virtualObjects.get(i);
172                sb.append(obj).append(" ").append(obj.getType().getName()).append(" ");
173                for (int j = 0; j < obj.getValues().length; j++) {
174                    sb.append(valueToString(obj.getValues()[j], virtualObjects)).append(' ');
175                }
176                sb.append("\n");
177
178            }
179        }
180        return sb.toString();
181    }
182
183    protected String valueToString(Value value, List<VirtualObject> virtualObjects) {
184        if (value == null) {
185            return "-";
186        }
187        if (value instanceof VirtualObject && !virtualObjects.contains(value)) {
188            virtualObjects.add((VirtualObject) value);
189        }
190        return value.toString();
191    }
192
193    public void printMachineCode(String code, String label) {
194        if (code == null || code.length() == 0) {
195            return;
196        }
197        if (label != null) {
198            begin("cfg");
199            out.print("name \"").print(label).println('"');
200            end("cfg");
201        }
202        begin("nmethod");
203        out.print(code);
204        out.println(" <|@");
205        end("nmethod");
206    }
207
208    public void printBytecodes(String code) {
209        if (code == null || code.length() == 0) {
210            return;
211        }
212        begin("bytecodes");
213        out.print(code);
214        out.println(" <|@");
215        end("bytecodes");
216    }
217}