/* * Copyright (c) 2011, 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 com.oracle.max.graal.compiler.debug; import java.io.*; import java.util.*; import com.oracle.max.criutils.*; import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.alloc.*; import com.oracle.max.graal.compiler.graphbuilder.*; import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.observer.*; import com.oracle.max.graal.compiler.schedule.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.nodes.*; import com.sun.cri.ci.*; import com.sun.cri.ri.*; /** * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the <a * href="http://java.net/projects/c1visualizer/">C1 Visualizer</a>. */ public class CFGPrinterObserver implements CompilationObserver { /** * A thread local stack of {@link CFGPrinter}s to support thread-safety and re-entrant compilation. */ private ThreadLocal<LinkedList<CFGPrinter>> observations = new ThreadLocal<LinkedList<CFGPrinter>>() { @Override protected java.util.LinkedList<CFGPrinter> initialValue() { return new LinkedList<CFGPrinter>(); } }; @Override public void compilationStarted(GraalCompilation compilation) { if (TTY.isSuppressed()) { return; } CFGPrinter cfgPrinter = new CFGPrinter(new ByteArrayOutputStream(), compilation); cfgPrinter.printCompilation(compilation.method); observations.get().push(cfgPrinter); } @Override public void compilationEvent(CompilationEvent event) { if (TTY.isSuppressed()) { return; } CFGPrinter cfgPrinter = observations.get().peek(); if (cfgPrinter == null) { return; } RiRuntime runtime = cfgPrinter.runtime; BlockMap blockMap = event.debugObject(BlockMap.class); Graph graph = event.debugObject(Graph.class); IdentifyBlocksPhase schedule = event.debugObject(IdentifyBlocksPhase.class); LIR lir = event.debugObject(LIR.class); LinearScan allocator = event.debugObject(LinearScan.class); Interval[] intervals = event.debugObject(Interval[].class); CiTargetMethod targetMethod = event.debugObject(CiTargetMethod.class); if (blockMap != null) { cfgPrinter.printCFG(event.label, blockMap); cfgPrinter.printBytecodes(runtime.disassemble(blockMap.method)); } if (lir != null) { cfgPrinter.printCFG(event.label, lir.codeEmittingOrder(), graph != null); if (targetMethod != null) { cfgPrinter.printMachineCode(runtime.disassemble(targetMethod), null); } } else if (graph != null) { List<? extends Block> blocks = null; if (schedule == null) { try { schedule = new IdentifyBlocksPhase(true, LIRBlock.FACTORY); schedule.apply((StructuredGraph) graph, false, false); blocks = schedule.getBlocks(); ComputeLinearScanOrder clso = new ComputeLinearScanOrder(schedule.getBlocks().size(), schedule.loopCount(), (LIRBlock) schedule.getStartBlock()); blocks = clso.codeEmittingOrder(); } catch (Throwable t) { // nothing to do here... } } if (blocks != null) { cfgPrinter.printCFG(event.label, blocks, true); } } if (allocator != null && intervals != null) { cfgPrinter.printIntervals(event.label, allocator, intervals); } } @Override public void compilationFinished(GraalCompilation compilation) { if (TTY.isSuppressed()) { return; } CFGPrinter cfgPrinter = observations.get().pop(); cfgPrinter.flush(); OutputStream stream = CompilationPrinter.globalOut(); if (stream != null) { synchronized (stream) { try { stream.write(cfgPrinter.buffer.toByteArray()); stream.flush(); } catch (IOException e) { TTY.println("WARNING: Error writing CFGPrinter output: %s", e); } } } } }