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 */ 23 package org.graalvm.compiler.printer; 24 25 import java.io.Closeable; 26 import java.io.File; 27 import java.io.FileNotFoundException; 28 import java.io.FileOutputStream; 29 import java.io.OutputStream; 30 import java.util.ArrayList; 31 import java.util.List; 32 import java.util.Map; 33 34 import org.graalvm.compiler.core.common.CompilationIdentifier; 35 import org.graalvm.compiler.debug.LogStream; 36 import org.graalvm.compiler.debug.TTY; 37 import org.graalvm.compiler.lir.util.IndexedValueMap; 38 39 import jdk.vm.ci.code.BytecodeFrame; 40 import jdk.vm.ci.code.BytecodePosition; 41 import jdk.vm.ci.code.ReferenceMap; 42 import jdk.vm.ci.code.Register; 43 import jdk.vm.ci.code.RegisterSaveLayout; 44 import jdk.vm.ci.code.VirtualObject; 45 import jdk.vm.ci.meta.JavaMethod; 46 import jdk.vm.ci.meta.JavaValue; 47 import jdk.vm.ci.meta.MetaUtil; 48 49 /** 50 * Utility for printing compilation related data structures at various compilation phases. The 51 * output format is such that it can then be fed to the 52 * <a href="https://c1visualizer.dev.java.net/">C1 Visualizer</a>. 53 */ 54 public class CompilationPrinter implements Closeable { 55 56 public static final String COLUMN_END = " <|@"; 57 public static final String HOVER_START = "<@"; 58 public static final String HOVER_SEP = "|@"; 59 public static final String HOVER_END = ">@"; 60 61 private static OutputStream globalOut; 62 63 /** 64 * Gets a global output stream on a file in the current working directory. This stream is first 65 * opened if necessary. The name of the file is 66 * {@code "compilations-" + System.currentTimeMillis() + ".cfg"}. 67 * 68 * @return the global output stream or {@code null} if there was an error opening the file for 69 * writing 70 */ 71 public static synchronized OutputStream globalOut() { 72 if (globalOut == null) { 73 File file = new File("compilations-" + System.currentTimeMillis() + ".cfg"); 74 try { 75 globalOut = new FileOutputStream(file); 76 } catch (FileNotFoundException e) { 77 TTY.println("WARNING: Could not open " + file.getAbsolutePath()); 78 } 79 } 80 return globalOut; 81 } 82 83 protected final LogStream out; 84 85 /** 86 * Creates a control flow graph printer. 87 * 88 * @param os where the output generated via this printer will be sent 89 */ 90 public CompilationPrinter(OutputStream os) { 91 out = new LogStream(os); 92 } 93 94 /** 95 * Flushes all buffered output to the underlying output stream. 96 */ 97 public void flush() { 98 out.flush(); 99 } 100 101 @Override 102 public void close() { 103 out.out().close(); 104 } 105 106 protected void begin(String string) { 107 out.println("begin_" + string); 108 out.adjustIndentation(2); 109 } 110 111 protected void end(String string) { 112 out.adjustIndentation(-2); 113 out.println("end_" + string); 114 } 115 116 /** 117 * Prints a compilation timestamp for a given method. 118 * 119 * @param javaMethod the method for which a timestamp will be printed 120 */ 121 public void printCompilation(JavaMethod javaMethod) { 122 printCompilation(javaMethod.format("%H::%n"), javaMethod.format("%f %r %H.%n(%p)")); 123 } 124 125 /** 126 * Prints a compilation id. 127 * 128 * @param compilationId the compilation method for which an id will be printed 129 */ 130 public void printCompilation(CompilationIdentifier compilationId) { 131 printCompilation(compilationId.toString(CompilationIdentifier.Verbosity.DETAILED), compilationId.toString(CompilationIdentifier.Verbosity.DETAILED)); 132 } 133 134 private void printCompilation(final String name, String method) { 135 begin("compilation"); 136 out.print("name \" ").print(name).println('"'); 137 out.print("method \"").print(method).println('"'); 138 out.print("date ").println(System.currentTimeMillis()); 139 end("compilation"); 140 } 141 142 /** 143 * Formats given debug info as a multi line string. 144 */ 145 protected String debugInfoToString(BytecodePosition codePos, ReferenceMap refMap, IndexedValueMap liveBasePointers, RegisterSaveLayout calleeSaveInfo) { 146 StringBuilder sb = new StringBuilder(); 147 if (refMap != null) { 148 sb.append("reference-map: "); 149 sb.append(refMap.toString()); 150 sb.append("\n"); 151 } 152 if (liveBasePointers != null) { 153 sb.append("live-base-pointers: "); 154 sb.append(liveBasePointers); 155 sb.append("\n"); 156 } 157 158 if (calleeSaveInfo != null) { 159 sb.append("callee-save-info:"); 160 for (Map.Entry<Register, Integer> e : calleeSaveInfo.registersToSlots(true).entrySet()) { 161 sb.append(" " + e.getKey() + " -> s" + e.getValue()); 162 } 163 sb.append("\n"); 164 } 165 166 if (codePos != null) { 167 BytecodePosition curCodePos = codePos; 168 List<VirtualObject> virtualObjects = new ArrayList<>(); 169 do { 170 sb.append(MetaUtil.toLocation(curCodePos.getMethod(), curCodePos.getBCI())); 171 sb.append('\n'); 172 if (curCodePos instanceof BytecodeFrame) { 173 BytecodeFrame frame = (BytecodeFrame) curCodePos; 174 if (frame.numStack > 0) { 175 sb.append("stack: "); 176 for (int i = 0; i < frame.numStack; i++) { 177 sb.append(valueToString(frame.getStackValue(i), virtualObjects)).append(' '); 178 } 179 sb.append("\n"); 180 } 181 sb.append("locals: "); 182 for (int i = 0; i < frame.numLocals; i++) { 183 sb.append(valueToString(frame.getLocalValue(i), virtualObjects)).append(' '); 184 } 185 sb.append("\n"); 186 if (frame.numLocks > 0) { 187 sb.append("locks: "); 188 for (int i = 0; i < frame.numLocks; ++i) { 189 sb.append(valueToString(frame.getLockValue(i), virtualObjects)).append(' '); 190 } 191 sb.append("\n"); 192 } 193 194 } 195 curCodePos = curCodePos.getCaller(); 196 } while (curCodePos != null); 197 198 for (int i = 0; i < virtualObjects.size(); i++) { 199 VirtualObject obj = virtualObjects.get(i); 200 sb.append(obj).append(" ").append(obj.getType().getName()).append(" "); 201 for (int j = 0; j < obj.getValues().length; j++) { 202 sb.append(valueToString(obj.getValues()[j], virtualObjects)).append(' '); 203 } 204 sb.append("\n"); 205 206 } 207 } 208 return sb.toString(); 209 } 210 211 protected String valueToString(JavaValue value, List<VirtualObject> virtualObjects) { 212 if (value == null) { 213 return "-"; 214 } 215 if (value instanceof VirtualObject && !virtualObjects.contains(value)) { 216 virtualObjects.add((VirtualObject) value); 217 } 218 return value.toString(); 219 } 220 221 public void printMachineCode(String code, String label) { 222 if (code == null || code.length() == 0) { 223 return; 224 } 225 if (label != null) { 226 begin("cfg"); 227 out.print("name \"").print(label).println('"'); 228 end("cfg"); 229 } 230 begin("nmethod"); 231 out.print(code); 232 out.println(" <|@"); 233 end("nmethod"); 234 } 235 236 public void printBytecodes(String code) { 237 if (code == null || code.length() == 0) { 238 return; 239 } 240 begin("bytecodes"); 241 out.print(code); 242 out.println(" <|@"); 243 end("bytecodes"); 244 } 245 }