/*
 * Copyright (c) 2011, 2015, 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 org.graalvm.compiler.printer;

import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.debug.LogStream;
import org.graalvm.compiler.debug.TTY;
import org.graalvm.compiler.lir.util.IndexedValueMap;

import jdk.vm.ci.code.BytecodeFrame;
import jdk.vm.ci.code.BytecodePosition;
import jdk.vm.ci.code.ReferenceMap;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.RegisterSaveLayout;
import jdk.vm.ci.code.VirtualObject;
import jdk.vm.ci.meta.JavaMethod;
import jdk.vm.ci.meta.JavaValue;
import jdk.vm.ci.meta.MetaUtil;

Utility for printing compilation related data structures at various compilation phases. The output format is such that it can then be fed to the C1 Visualizer.
/** * 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 implements Closeable { 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 "compilations-" + System.currentTimeMillis() + ".cfg".
Returns:the global output stream or null if there was an error opening the file for writing
/** * 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.
Params:
  • os – where the output generated via this printer will be sent
/** * 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.
/** * Flushes all buffered output to the underlying output stream. */
public void flush() { out.flush(); } @Override public void close() { out.out().close(); } 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.
Params:
  • javaMethod – the method for which a timestamp will be printed
/** * Prints a compilation timestamp for a given method. * * @param javaMethod the method for which a timestamp will be printed */
public void printCompilation(JavaMethod javaMethod) { printCompilation(javaMethod.format("%H::%n"), javaMethod.format("%f %r %H.%n(%p)")); }
Prints a compilation id.
Params:
  • compilationId – the compilation method for which an id will be printed
/** * Prints a compilation id. * * @param compilationId the compilation method for which an id will be printed */
public void printCompilation(CompilationIdentifier compilationId) { printCompilation(compilationId.toString(CompilationIdentifier.Verbosity.DETAILED), compilationId.toString(CompilationIdentifier.Verbosity.DETAILED)); } private void printCompilation(final String name, String method) { begin("compilation"); out.print("name \" ").print(name).println('"'); out.print("method \"").print(method).println('"'); out.print("date ").println(System.currentTimeMillis()); end("compilation"); }
Formats given debug info as a multi line string.
/** * Formats given debug info as a multi line string. */
protected String debugInfoToString(BytecodePosition codePos, ReferenceMap refMap, IndexedValueMap liveBasePointers, RegisterSaveLayout calleeSaveInfo) { StringBuilder sb = new StringBuilder(); if (refMap != null) { sb.append("reference-map: "); sb.append(refMap.toString()); sb.append("\n"); } if (liveBasePointers != null) { sb.append("live-base-pointers: "); sb.append(liveBasePointers); sb.append("\n"); } if (calleeSaveInfo != null) { sb.append("callee-save-info:"); for (Map.Entry<Register, Integer> e : calleeSaveInfo.registersToSlots(true).entrySet()) { sb.append(" " + e.getKey() + " -> s" + e.getValue()); } sb.append("\n"); } if (codePos != null) { BytecodePosition curCodePos = codePos; List<VirtualObject> virtualObjects = new ArrayList<>(); do { sb.append(MetaUtil.toLocation(curCodePos.getMethod(), curCodePos.getBCI())); sb.append('\n'); if (curCodePos instanceof BytecodeFrame) { BytecodeFrame frame = (BytecodeFrame) curCodePos; if (frame.numStack > 0) { sb.append("stack: "); for (int i = 0; i < frame.numStack; i++) { sb.append(valueToString(frame.getStackValue(i), virtualObjects)).append(' '); } sb.append("\n"); } sb.append("locals: "); for (int i = 0; i < frame.numLocals; i++) { sb.append(valueToString(frame.getLocalValue(i), virtualObjects)).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), virtualObjects)).append(' '); } sb.append("\n"); } } curCodePos = curCodePos.getCaller(); } while (curCodePos != null); for (int i = 0; i < virtualObjects.size(); i++) { VirtualObject obj = virtualObjects.get(i); sb.append(obj).append(" ").append(obj.getType().getName()).append(" "); for (int j = 0; j < obj.getValues().length; j++) { sb.append(valueToString(obj.getValues()[j], virtualObjects)).append(' '); } sb.append("\n"); } } return sb.toString(); } protected String valueToString(JavaValue value, List<VirtualObject> virtualObjects) { if (value == null) { return "-"; } if (value instanceof VirtualObject && !virtualObjects.contains(value)) { virtualObjects.add((VirtualObject) value); } return value.toString(); } public void printMachineCode(String code, String label) { if (code == null || 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 == null || code.length() == 0) { return; } begin("bytecodes"); out.print(code); out.println(" <|@"); end("bytecodes"); } }