CompilationPrinter.java revision 12657:6ef01bd40ce2
1/*
2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package org.graalvm.compiler.printer;
24
25import java.io.Closeable;
26import java.io.File;
27import java.io.FileNotFoundException;
28import java.io.FileOutputStream;
29import java.io.OutputStream;
30import java.util.ArrayList;
31import java.util.List;
32import java.util.Map;
33
34import org.graalvm.compiler.debug.LogStream;
35import org.graalvm.compiler.debug.TTY;
36import org.graalvm.compiler.lir.util.IndexedValueMap;
37
38import jdk.vm.ci.code.BytecodeFrame;
39import jdk.vm.ci.code.BytecodePosition;
40import jdk.vm.ci.code.ReferenceMap;
41import jdk.vm.ci.code.Register;
42import jdk.vm.ci.code.RegisterSaveLayout;
43import jdk.vm.ci.code.VirtualObject;
44import jdk.vm.ci.meta.JavaMethod;
45import jdk.vm.ci.meta.JavaValue;
46import jdk.vm.ci.meta.MetaUtil;
47
48/**
49 * Utility for printing compilation related data structures at various compilation phases. The
50 * output format is such that it can then be fed to the
51 * <a href="https://c1visualizer.dev.java.net/">C1 Visualizer</a>.
52 */
53public class CompilationPrinter implements Closeable {
54
55    public static final String COLUMN_END = " <|@";
56    public static final String HOVER_START = "<@";
57    public static final String HOVER_SEP = "|@";
58    public static final String HOVER_END = ">@";
59
60    private static OutputStream globalOut;
61
62    /**
63     * Gets a global output stream on a file in the current working directory. This stream is first
64     * opened if necessary. The name of the file is
65     * {@code "compilations-" + System.currentTimeMillis() + ".cfg"}.
66     *
67     * @return the global output stream or {@code null} if there was an error opening the file for
68     *         writing
69     */
70    public static synchronized OutputStream globalOut() {
71        if (globalOut == null) {
72            File file = new File("compilations-" + System.currentTimeMillis() + ".cfg");
73            try {
74                globalOut = new FileOutputStream(file);
75            } catch (FileNotFoundException e) {
76                TTY.println("WARNING: Could not open " + file.getAbsolutePath());
77            }
78        }
79        return globalOut;
80    }
81
82    protected final LogStream out;
83
84    /**
85     * Creates a control flow graph printer.
86     *
87     * @param os where the output generated via this printer will be sent
88     */
89    public CompilationPrinter(OutputStream os) {
90        out = new LogStream(os);
91    }
92
93    /**
94     * Flushes all buffered output to the underlying output stream.
95     */
96    public void flush() {
97        out.flush();
98    }
99
100    @Override
101    public void close() {
102        out.out().close();
103    }
104
105    protected void begin(String string) {
106        out.println("begin_" + string);
107        out.adjustIndentation(2);
108    }
109
110    protected void end(String string) {
111        out.adjustIndentation(-2);
112        out.println("end_" + string);
113    }
114
115    /**
116     * Prints a compilation timestamp for a given method.
117     *
118     * @param method the method for which a timestamp will be printed
119     */
120    public void printCompilation(JavaMethod method) {
121        begin("compilation");
122        out.print("name \" ").print(method.format("%H::%n")).println('"');
123        out.print("method \"").print(method.format("%f %r %H.%n(%p)")).println('"');
124        out.print("date ").println(System.currentTimeMillis());
125        end("compilation");
126    }
127
128    /**
129     * Formats given debug info as a multi line string.
130     */
131    protected String debugInfoToString(BytecodePosition codePos, ReferenceMap refMap, IndexedValueMap liveBasePointers, RegisterSaveLayout calleeSaveInfo) {
132        StringBuilder sb = new StringBuilder();
133        if (refMap != null) {
134            sb.append("reference-map: ");
135            sb.append(refMap.toString());
136            sb.append("\n");
137        }
138        if (liveBasePointers != null) {
139            sb.append("live-base-pointers: ");
140            sb.append(liveBasePointers);
141            sb.append("\n");
142        }
143
144        if (calleeSaveInfo != null) {
145            sb.append("callee-save-info:");
146            for (Map.Entry<Register, Integer> e : calleeSaveInfo.registersToSlots(true).entrySet()) {
147                sb.append(" " + e.getKey() + " -> s" + e.getValue());
148            }
149            sb.append("\n");
150        }
151
152        if (codePos != null) {
153            BytecodePosition curCodePos = codePos;
154            List<VirtualObject> virtualObjects = new ArrayList<>();
155            do {
156                sb.append(MetaUtil.toLocation(curCodePos.getMethod(), curCodePos.getBCI()));
157                sb.append('\n');
158                if (curCodePos instanceof BytecodeFrame) {
159                    BytecodeFrame frame = (BytecodeFrame) curCodePos;
160                    if (frame.numStack > 0) {
161                        sb.append("stack: ");
162                        for (int i = 0; i < frame.numStack; i++) {
163                            sb.append(valueToString(frame.getStackValue(i), virtualObjects)).append(' ');
164                        }
165                        sb.append("\n");
166                    }
167                    sb.append("locals: ");
168                    for (int i = 0; i < frame.numLocals; i++) {
169                        sb.append(valueToString(frame.getLocalValue(i), virtualObjects)).append(' ');
170                    }
171                    sb.append("\n");
172                    if (frame.numLocks > 0) {
173                        sb.append("locks: ");
174                        for (int i = 0; i < frame.numLocks; ++i) {
175                            sb.append(valueToString(frame.getLockValue(i), virtualObjects)).append(' ');
176                        }
177                        sb.append("\n");
178                    }
179
180                }
181                curCodePos = curCodePos.getCaller();
182            } while (curCodePos != null);
183
184            for (int i = 0; i < virtualObjects.size(); i++) {
185                VirtualObject obj = virtualObjects.get(i);
186                sb.append(obj).append(" ").append(obj.getType().getName()).append(" ");
187                for (int j = 0; j < obj.getValues().length; j++) {
188                    sb.append(valueToString(obj.getValues()[j], virtualObjects)).append(' ');
189                }
190                sb.append("\n");
191
192            }
193        }
194        return sb.toString();
195    }
196
197    protected String valueToString(JavaValue value, List<VirtualObject> virtualObjects) {
198        if (value == null) {
199            return "-";
200        }
201        if (value instanceof VirtualObject && !virtualObjects.contains(value)) {
202            virtualObjects.add((VirtualObject) value);
203        }
204        return value.toString();
205    }
206
207    public void printMachineCode(String code, String label) {
208        if (code == null || code.length() == 0) {
209            return;
210        }
211        if (label != null) {
212            begin("cfg");
213            out.print("name \"").print(label).println('"');
214            end("cfg");
215        }
216        begin("nmethod");
217        out.print(code);
218        out.println(" <|@");
219        end("nmethod");
220    }
221
222    public void printBytecodes(String code) {
223        if (code == null || code.length() == 0) {
224            return;
225        }
226        begin("bytecodes");
227        out.print(code);
228        out.println(" <|@");
229        end("bytecodes");
230    }
231}
232