/* * Copyright (c) 2013, 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.truffle; import org.graalvm.compiler.debug.DebugDumpHandler; import org.graalvm.compiler.debug.GraalDebugConfig.Options; import org.graalvm.compiler.options.OptionValues; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.GraphPrintVisitor; import com.oracle.truffle.api.nodes.GraphPrintVisitor.GraphPrintAdapter; import com.oracle.truffle.api.nodes.GraphPrintVisitor.GraphPrintHandler; import com.oracle.truffle.api.nodes.NodeUtil; import com.oracle.truffle.api.source.SourceSection; public class TruffleTreeDumpHandler implements DebugDumpHandler { /** * The {@link OptimizedCallTarget} is dumped multiple times during Graal compilation, because it * is also a subclass of InstalledCode. To disambiguate dumping, we wrap the call target into * this class when we want to dump the truffle tree. */ public static class TruffleTreeDump { final RootCallTarget callTarget; public TruffleTreeDump(RootCallTarget callTarget) { this.callTarget = callTarget; } } private final OptionValues options; public TruffleTreeDumpHandler(OptionValues options) { this.options = options; } @Override public void dump(Object object, final String message) { if (object instanceof TruffleTreeDump && Options.PrintGraph.getValue(options) && TruffleCompilerOptions.getValue(Options.PrintTruffleTrees)) { dumpRootCallTarget(message, ((TruffleTreeDump) object).callTarget); } } private static void dumpRootCallTarget(final String message, RootCallTarget callTarget) { if (callTarget.getRootNode() != null) { final GraphPrintVisitor printer = new GraphPrintVisitor(); printer.beginGroup(callTarget.toString()); printer.beginGraph(message).visit(callTarget.getRootNode()).endGraph(); if (callTarget instanceof OptimizedCallTarget) { TruffleInlining inlining = new TruffleInlining((OptimizedCallTarget) callTarget, new DefaultInliningPolicy()); if (inlining.countInlinedCalls() > 0) { dumpInlinedTrees(printer, (OptimizedCallTarget) callTarget, inlining); dumpInlinedCallGraph(printer, (OptimizedCallTarget) callTarget, inlining); } } printer.endGroup(); printer.printToNetwork(false); } } private static void dumpInlinedTrees(final GraphPrintVisitor printer, final OptimizedCallTarget callTarget, TruffleInlining inlining) { for (DirectCallNode callNode : NodeUtil.findAllNodeInstances(callTarget.getRootNode(), DirectCallNode.class)) { CallTarget inlinedCallTarget = callNode.getCurrentCallTarget(); if (inlinedCallTarget instanceof OptimizedCallTarget && callNode instanceof OptimizedDirectCallNode) { TruffleInliningDecision decision = inlining.findByCall((OptimizedDirectCallNode) callNode); if (decision != null && decision.isInline()) { printer.beginGroup(inlinedCallTarget.toString()); printer.beginGraph(inlinedCallTarget.toString()).visit(((RootCallTarget) inlinedCallTarget).getRootNode()).endGraph(); dumpInlinedTrees(printer, (OptimizedCallTarget) inlinedCallTarget, decision); printer.endGroup(); } } } } private static void dumpInlinedCallGraph(final GraphPrintVisitor printer, final OptimizedCallTarget rootCallTarget, TruffleInlining inlining) { class InliningGraphPrintHandler implements GraphPrintHandler { private final TruffleInlining inlining; InliningGraphPrintHandler(TruffleInlining inlining) { this.inlining = inlining; } @Override public void visit(Object node, GraphPrintAdapter g) { if (g.visited(node)) { return; } g.createElementForNode(node); g.setNodeProperty(node, "name", node.toString()); for (DirectCallNode callNode : NodeUtil.findAllNodeInstances(((RootCallTarget) node).getRootNode(), DirectCallNode.class)) { CallTarget inlinedCallTarget = callNode.getCurrentCallTarget(); if (inlinedCallTarget instanceof OptimizedCallTarget && callNode instanceof OptimizedDirectCallNode) { TruffleInliningDecision decision = inlining.findByCall((OptimizedDirectCallNode) callNode); if (decision != null && decision.isInline()) { g.visit(inlinedCallTarget, new InliningGraphPrintHandler(decision)); SourceSection sourceSection = callNode.getEncapsulatingSourceSection(); g.connectNodes(node, inlinedCallTarget, sourceSection != null ? sourceSection.toString() : null); } } } } } printer.beginGraph("inlined call graph"); printer.visit(rootCallTarget, new InliningGraphPrintHandler(inlining)); printer.endGraph(); } @Override public void close() { // nothing to do } }