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}