# HG changeset patch # User Christian Humer # Date 1412868324 -7200 # Node ID e3dd05527c2f117b93e0d956c1be8a1021cb5222 # Parent 5787218bad9174c518226cd80b2c6aee07f7371a Truffle: enabled context sensitive inlining by default. removed old inlining structures. diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Thu Oct 09 17:25:24 2014 +0200 @@ -95,7 +95,7 @@ } private static void installOptimizedCallTargetCallDirect() { - if (TruffleCompilerOptions.TruffleContextSensitiveInlining.getValue()) { + if (TruffleCompilerOptions.TruffleFunctionInlining.getValue()) { ((HotSpotResolvedJavaMethod) getGraalProviders().getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallDirectMethod())).setNotInlineable(); } } diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Thu Oct 09 17:25:24 2014 +0200 @@ -93,11 +93,10 @@ compilable.call(arguments); compilable.call(arguments); compilable.call(arguments); - compilable.performInlining(); try (Scope s = Debug.scope("TruffleCompilation", new TruffleDebugJavaMethod(compilable))) { - StructuredGraph resultGraph = truffleCompiler.getPartialEvaluator().createGraph(compilable, assumptions, null); + StructuredGraph resultGraph = truffleCompiler.getPartialEvaluator().createGraph(compilable, assumptions); CanonicalizerPhase canonicalizer = new CanonicalizerPhase(canonicalizeReads); PhaseContext context = new PhaseContext(getProviders(), assumptions); diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/ContextSensitiveInlining.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/ContextSensitiveInlining.java Thu Oct 09 17:25:18 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,218 +0,0 @@ -/* - * 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 com.oracle.graal.truffle; - -import java.util.*; -import java.util.stream.*; - -import com.oracle.graal.truffle.ContextSensitiveInlining.InliningDecision; - -public class ContextSensitiveInlining implements Iterable { - - private final List callSites; - - private ContextSensitiveInlining(List callSites) { - this.callSites = callSites; - } - - public ContextSensitiveInlining(OptimizedCallTarget sourceTarget, TruffleInliningPolicy policy) { - this(createDecisions(sourceTarget, policy)); - } - - private static List createDecisions(OptimizedCallTarget sourceTarget, TruffleInliningPolicy policy) { - int nodeCount = OptimizedCallUtils.countNonTrivialNodes(sourceTarget, false); - List exploredCallSites = exploreCallSites(new ArrayList<>(Arrays.asList(sourceTarget)), nodeCount, policy); - return decideInlining(exploredCallSites, policy, nodeCount); - } - - private static List exploreCallSites(List stack, int callStackNodeCount, TruffleInliningPolicy policy) { - List exploredCallSites = new ArrayList<>(); - OptimizedCallTarget parentTarget = stack.get(stack.size() - 1); - for (OptimizedDirectCallNode callNode : parentTarget.getCallNodes()) { - OptimizedCallTarget currentTarget = callNode.getCurrentCallTarget(); - stack.add(currentTarget); // push - exploredCallSites.add(exploreCallSite(stack, callStackNodeCount, policy, callNode)); - stack.remove(stack.size() - 1); // pop - } - return exploredCallSites; - } - - private static InliningDecision exploreCallSite(List callStack, int callStackNodeCount, TruffleInliningPolicy policy, OptimizedDirectCallNode callNode) { - OptimizedCallTarget parentTarget = callStack.get(callStack.size() - 2); - OptimizedCallTarget currentTarget = callStack.get(callStack.size() - 1); - - boolean recursive = isRecursiveStack(callStack); - boolean maxDepth = callStack.size() >= 15; - - List childCallSites = Collections.emptyList(); - double frequency = TruffleInliningHandler.calculateFrequency(parentTarget, callNode); - int nodeCount = OptimizedCallUtils.countNonTrivialNodes(callNode.getCurrentCallTarget(), false); - - int deepNodeCount = nodeCount; - if (!recursive && !maxDepth) { - /* - * We make a preliminary optimistic inlining decision with best possible characteristics - * to avoid the exploration of unnecessary pathes in the inlining tree. - */ - if (policy.isAllowed(new TruffleInliningProfile(callNode, nodeCount, nodeCount, frequency, recursive, null), callStackNodeCount)) { - List exploredCallSites = exploreCallSites(callStack, callStackNodeCount + nodeCount, policy); - childCallSites = decideInlining(exploredCallSites, policy, nodeCount); - for (InliningDecision childCallSite : childCallSites) { - if (childCallSite.isInline()) { - deepNodeCount += childCallSite.getProfile().getDeepNodeCount(); - } else { - /* we don't need those anymore. */ - childCallSite.getCallSites().clear(); - } - } - } - } - - TruffleInliningProfile profile = new TruffleInliningProfile(callNode, nodeCount, deepNodeCount, frequency, recursive, null); - profile.setScore(policy.calculateScore(profile)); - return new InliningDecision(currentTarget, profile, childCallSites); - } - - private static boolean isRecursiveStack(List stack) { - OptimizedCallTarget top = stack.get(stack.size() - 1); - for (int i = 0; i < stack.size() - 1; i++) { - if (stack.get(i) == top) { - return true; - } - } - return false; - } - - private static List decideInlining(List callSites, TruffleInliningPolicy policy, int nodeCount) { - int deepNodeCount = nodeCount; - int index = 0; - for (InliningDecision callSite : callSites.stream().sorted().collect(Collectors.toList())) { - TruffleInliningProfile profile = callSite.getProfile(); - profile.setQueryIndex(index++); - if (policy.isAllowed(profile, deepNodeCount)) { - callSite.setInline(true); - deepNodeCount += profile.getDeepNodeCount(); - } - } - return callSites; - } - - public boolean isInlined(List callNodeTrace) { - if (callNodeTrace.isEmpty()) { - return false; - } - - InliningDecision prev = null; - for (int i = 0; i < callNodeTrace.size(); i++) { - if (prev == null) { - prev = findByCall(callNodeTrace.get(i)); - } else { - prev = prev.findByCall(callNodeTrace.get(i)); - } - if (prev == null || !prev.isInline()) { - return false; - } - } - return true; - } - - public int countCalls() { - return callSites.stream().mapToInt(callSite -> callSite.isInline() ? callSite.countCalls() + 1 : 1).sum(); - } - - public int countInlinedCalls() { - return callSites.stream().filter(InliningDecision::isInline).mapToInt(callSite -> callSite.countInlinedCalls() + 1).sum(); - } - - public List getCallSites() { - return callSites; - } - - public Iterator iterator() { - return callSites.iterator(); - } - - public InliningDecision findByCall(OptimizedDirectCallNode callNode) { - return getCallSites().stream().filter(c -> c.getProfile().getCallNode() == callNode).findFirst().orElse(null); - } - - public static final class InliningDecision extends ContextSensitiveInlining implements Comparable { - - private final OptimizedCallTarget target; - private final TruffleInliningProfile profile; - private boolean inline; - - public InliningDecision(OptimizedCallTarget target, TruffleInliningProfile profile, List children) { - super(children); - this.target = target; - this.profile = profile; - } - - public OptimizedCallTarget getTarget() { - return target; - } - - public void setInline(boolean inline) { - this.inline = inline; - } - - public boolean isInline() { - return inline; - } - - public TruffleInliningProfile getProfile() { - return profile; - } - - public int compareTo(InliningDecision o) { - return Double.compare(o.getProfile().getScore(), getProfile().getScore()); - } - - public boolean isSameAs(InliningDecision other) { - if (getTarget() != other.getTarget()) { - return false; - } else if (isInline() != other.isInline()) { - return false; - } else if (!isInline()) { - assert !other.isInline(); - return true; - } else { - Iterator i1 = iterator(); - Iterator i2 = other.iterator(); - while (i1.hasNext() && i2.hasNext()) { - if (!i1.next().isSameAs(i2.next())) { - return false; - } - } - return !i1.hasNext() && !i2.hasNext(); - } - } - - @Override - public String toString() { - return String.format("InliningDecision(callNode=%s, inline=%b)", profile.getCallNode(), inline); - } - - } - -} diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategy.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategy.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategy.java Thu Oct 09 17:25:24 2014 +0200 @@ -34,7 +34,7 @@ } public void beforeCall(Object[] arguments) { - if (call.getCallCount() == 2 && !call.isInlined()) { + if (call.getCallCount() == 2) { if (shouldSplit()) { forceSplitting(); } diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalFrameInstance.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalFrameInstance.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalFrameInstance.java Thu Oct 09 17:25:24 2014 +0200 @@ -87,14 +87,14 @@ /** * This class represents a frame that is taken from the - * {@link OptimizedDirectCallNode#callProxy(MaterializedFrameNotify, CallTarget, VirtualFrame, Object[], boolean, boolean)} + * {@link OptimizedDirectCallNode#callProxy(MaterializedFrameNotify, CallTarget, VirtualFrame, Object[], boolean)} * method. */ public static final class CallNodeFrame extends GraalFrameInstance { public static final Method METHOD; static { try { - METHOD = OptimizedDirectCallNode.class.getDeclaredMethod("callProxy", MaterializedFrameNotify.class, CallTarget.class, VirtualFrame.class, Object[].class, boolean.class, boolean.class); + METHOD = OptimizedDirectCallNode.class.getDeclaredMethod("callProxy", MaterializedFrameNotify.class, CallTarget.class, VirtualFrame.class, Object[].class, boolean.class); } catch (NoSuchMethodException | SecurityException e) { throw new GraalInternalError(e); } diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Thu Oct 09 17:25:24 2014 +0200 @@ -29,15 +29,16 @@ import java.lang.reflect.*; import java.util.*; import java.util.concurrent.atomic.*; +import java.util.stream.*; import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.debug.*; -import com.oracle.graal.truffle.ContextSensitiveInlining.InliningDecision; import com.oracle.truffle.api.*; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.Node; /** * Call target that is optimized by Graal upon surpassing a specific invocation threshold. @@ -66,7 +67,7 @@ private TruffleStamp argumentStamp = DefaultTruffleStamp.getInstance(); /* Experimental field for context sensitive inlining. */ - private ContextSensitiveInlining inliningDecision; + private TruffleInlining inlining; public final RootNode getRootNode() { return rootNode; @@ -256,49 +257,18 @@ if (isValid()) { CompilerAsserts.neverPartOfCompilation(); invalidate(); - invalidateInlining(); compilationProfile.reportInvalidated(); logOptimizedInvalidated(this, oldNode, newNode, reason); } cancelInstalledTask(oldNode, newNode, reason); - // invalidateInlining(); } - public void invalidateInlining() { - if (inliningPerformed) { - inliningPerformed = false; - getRootNode().accept(new NodeVisitor() { - public boolean visit(Node node) { - if (node instanceof OptimizedDirectCallNode) { - OptimizedDirectCallNode callNode = (OptimizedDirectCallNode) node; - if (callNode.isInlined()) { - callNode.resetInlining(); - } - } - return true; - } - }); - } + public TruffleInlining getInlining() { + return inlining; } - public ContextSensitiveInlining getInliningDecision() { - return inliningDecision; - } - - public void setInliningDecision(ContextSensitiveInlining inliningDecision) { - this.inliningDecision = inliningDecision; - } - - public boolean isInlined(List callNodeTrace) { - if (TruffleCompilerOptions.TruffleContextSensitiveInlining.getValue()) { - if (inliningDecision == null) { - return false; - } else { - return inliningDecision.isInlined(callNodeTrace); - } - } else { - return callNodeTrace.get(callNodeTrace.size() - 1).isInlined(); - } + public void setInlining(TruffleInlining inliningDecision) { + this.inlining = inliningDecision; } private void cancelInstalledTask(Node oldNode, Node newNode, CharSequence reason) { @@ -326,7 +296,6 @@ public void compile() { if (!runtime.isCompiling(this)) { - performInlining(); logOptimizingQueued(this); runtime.compile(this, TruffleBackgroundCompilation.getValue()); } @@ -335,8 +304,8 @@ public void compilationFinished(Throwable t) { if (t == null) { // Compilation was successful. - if (inliningDecision != null) { - dequeueInlinedCallSites(inliningDecision); + if (inlining != null) { + dequeueInlinedCallSites(inlining); } } else { if (!(t instanceof BailoutException) || ((BailoutException) t).isPermanent()) { @@ -346,7 +315,7 @@ if (TruffleCompilationExceptionsAreThrown.getValue()) { throw new OptimizationFailedException(t, rootNode); } - logOptimizingFailed(this, t.getMessage()); + logOptimizingFailed(this, t.toString()); if (t instanceof BailoutException) { // Bailout => move on. } else if (TruffleCompilationExceptionsAreFatal.getValue()) { @@ -356,10 +325,10 @@ } } - private void dequeueInlinedCallSites(ContextSensitiveInlining parentDecision) { - for (InliningDecision decision : parentDecision) { + private void dequeueInlinedCallSites(TruffleInlining parentDecision) { + for (TruffleInliningDecision decision : parentDecision) { if (decision.isInline()) { - OptimizedCallTarget target = decision.getProfile().getCallNode().getCurrentCallTarget(); + OptimizedCallTarget target = decision.getTarget(); if (runtime.cancelInstalledTask(target)) { logOptimizingUnqueued(target, null, null, "Inlining caller compiled."); } @@ -413,33 +382,6 @@ return compilationProfile; } - public final void performInlining() { - if (!TruffleFunctionInlining.getValue() || TruffleContextSensitiveInlining.getValue()) { - return; - } - if (inliningPerformed) { - return; - } - TruffleInliningHandler handler = new TruffleInliningHandler(new DefaultInliningPolicy()); - TruffleInliningDecision result = handler.decideInlining(this, 0); - performInlining(result); - logInliningDecision(result); - } - - private static void performInlining(TruffleInliningDecision result) { - if (result.getCallTarget().inliningPerformed) { - return; - } - result.getCallTarget().inliningPerformed = true; - for (TruffleInliningProfile profile : result) { - profile.getCallNode().inline(); - TruffleInliningDecision recursiveResult = profile.getRecursiveResult(); - if (recursiveResult != null) { - performInlining(recursiveResult); - } - } - } - @ExplodeLoop private Object[] castArguments(Object[] originalArguments) { Object[] castArguments = new Object[profiledArgumentTypes.length]; @@ -497,7 +439,6 @@ addASTSizeProperty(this, properties); properties.putAll(getCompilationProfile().getDebugProperties()); return properties; - } public static Method getCallDirectMethod() { diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java Thu Oct 09 17:25:24 2014 +0200 @@ -28,9 +28,8 @@ import java.util.*; import com.oracle.graal.debug.*; -import com.oracle.graal.truffle.ContextSensitiveInlining.InliningDecision; +import com.oracle.graal.truffle.TruffleInlining.CallTreeNodeVisitor; import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.nodes.NodeUtil.NodeCountFilter; public final class OptimizedCallTargetLog { @@ -55,8 +54,8 @@ } public static void logInliningDecision(OptimizedCallTarget target) { - ContextSensitiveInlining inlining = target.getInliningDecision(); - if (!TraceTruffleInlining.getValue() || inlining == null) { + TruffleInlining inlining = target.getInlining(); + if (inlining == null) { return; } @@ -65,8 +64,8 @@ logInliningDone(target); } - private static void logInliningDecisionRecursive(ContextSensitiveInlining result, int depth) { - for (InliningDecision decision : result) { + private static void logInliningDecisionRecursive(TruffleInlining result, int depth) { + for (TruffleInliningDecision decision : result) { TruffleInliningProfile profile = decision.getProfile(); boolean inlined = decision.isInline(); String msg = inlined ? "inline success" : "inline failed"; @@ -77,36 +76,12 @@ } } - public static void logInliningDecision(TruffleInliningDecision result) { - if (!TraceTruffleInlining.getValue()) { - return; - } - - logInliningStart(result.getCallTarget()); - logInliningDecisionRecursive(result, 0); - logInliningDone(result.getCallTarget()); - } + public static void logTruffleCalls(OptimizedCallTarget compilable) { + CallTreeNodeVisitor visitor = new CallTreeNodeVisitor() { - private static void logInliningDecisionRecursive(TruffleInliningDecision result, int depth) { - List callNodes = searchCallNodes(result.getCallTarget()); - for (OptimizedDirectCallNode callNode : callNodes) { - TruffleInliningProfile profile = result.getProfiles().get(callNode); - boolean inlined = result.isInlined(callNode); - String msg = inlined ? "inline success" : "inline failed"; - logInlinedImpl(msg, callNode, profile, depth); - if (profile.getRecursiveResult() != null && inlined) { - logInliningDecisionRecursive(profile.getRecursiveResult(), depth + 1); - } - } - } - - public static void logTruffleCalls(OptimizedCallTarget compilable) { - compilable.getRootNode().accept(new NodeVisitor() { - - int depth = 1; - - public boolean visit(Node node) { + public boolean visit(List decisionStack, Node node) { if (node instanceof OptimizedDirectCallNode) { + int depth = decisionStack == null ? 0 : decisionStack.size(); OptimizedDirectCallNode callNode = ((OptimizedDirectCallNode) node); String dispatched = !callNode.isInlined() ? " " : ""; Map properties = new LinkedHashMap<>(); @@ -114,31 +89,21 @@ properties.putAll(callNode.getCurrentCallTarget().getDebugProperties()); properties.put("Stamp", callNode.getCurrentCallTarget().getArgumentStamp()); log((depth * 2), "call", callNode.getCurrentCallTarget().toString() + dispatched, properties); - - if (callNode.isInlined()) { - depth++; - callNode.getCurrentRootNode().accept(this); - depth--; - } } else if (node instanceof OptimizedIndirectCallNode) { + int depth = decisionStack == null ? 0 : decisionStack.size(); log((depth * 2), "call", "", new LinkedHashMap()); } return true; } - }); - } + + }; - private static List searchCallNodes(final OptimizedCallTarget target) { - final List callNodes = new ArrayList<>(); - target.getRootNode().accept(new NodeVisitor() { - public boolean visit(Node node) { - if (node instanceof OptimizedDirectCallNode) { - callNodes.add((OptimizedDirectCallNode) node); - } - return true; - } - }); - return callNodes; + TruffleInlining inlining = compilable.getInlining(); + if (inlining == null) { + compilable.getRootNode().accept(visitor); + } else { + inlining.accept(compilable, visitor); + } } private static void logInlinedImpl(String status, OptimizedDirectCallNode callNode, TruffleInliningProfile profile, int depth) { @@ -247,26 +212,13 @@ } public static void addASTSizeProperty(OptimizedCallTarget target, Map properties) { - if (TruffleContextSensitiveInlining.getValue() && target.getInliningDecision() != null) { - int deepCount = target.getInliningDecision().getCallSites().stream().filter(callSite -> callSite.isInline()).mapToInt(callSite -> callSite.getProfile().getDeepNodeCount()).sum(); - long nodeCount = OptimizedCallUtils.countNonTrivialNodes(target, false); - properties.put("ASTSize", String.format("%5d/%5d", nodeCount, nodeCount + deepCount)); - } else { - int polymorphicCount = NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() { - public boolean isCounted(Node node) { - return node.getCost() == NodeCost.POLYMORPHIC; - } - }, true); - - int megamorphicCount = NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() { - public boolean isCounted(Node node) { - return node.getCost() == NodeCost.MEGAMORPHIC; - } - }, true); - - String value = String.format("%4d (%d/%d)", OptimizedCallUtils.countNonTrivialNodes(target, true), polymorphicCount, megamorphicCount); - properties.put("ASTSize", value); + int nodeCount = OptimizedCallUtils.countNonTrivialNodes(target, false); + int deepNodeCount = nodeCount; + TruffleInlining inlining = target.getInlining(); + if (inlining != null) { + deepNodeCount += inlining.getInlinedNodeCount(); } + properties.put("ASTSize", String.format("%5d/%5d", nodeCount, deepNodeCount)); } diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java Thu Oct 09 17:25:24 2014 +0200 @@ -23,99 +23,66 @@ package com.oracle.graal.truffle; import java.io.*; +import java.util.*; +import com.oracle.graal.truffle.TruffleInlining.CallTreeNodeVisitor; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.nodes.NodeUtil.NodeClass; -import com.oracle.truffle.api.nodes.NodeUtil.NodeCountFilter; import com.oracle.truffle.api.nodes.NodeUtil.NodeField; public class OptimizedCallUtils { - public static int countCalls(OptimizedCallTarget target) { - ContextSensitiveInlining inlining = target.getInliningDecision(); - if (inlining != null) { - return inlining.countCalls(); - } else { - return NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() { - public boolean isCounted(Node node) { - return node instanceof DirectCallNode; - } - }, true); - } + public static int countNonTrivialNodes(final OptimizedCallTarget target, final boolean inlined) { + return (int) target.nodeStream(inlined).filter(e -> e != null && !e.getCost().isTrivial()).count(); } - public static int countCallsInlined(OptimizedCallTarget target) { - ContextSensitiveInlining inlining = target.getInliningDecision(); - if (inlining != null) { - return inlining.countInlinedCalls(); - } else { - return NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() { - public boolean isCounted(Node node) { - return (node instanceof OptimizedDirectCallNode) && ((OptimizedDirectCallNode) node).isInlined(); - } - }, true); - } - } - - public static int countNonTrivialNodes(final OptimizedCallTarget target, final boolean inlined) { - return NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() { - public boolean isCounted(Node node) { - NodeCost cost = node.getCost(); - if (cost != null && cost != NodeCost.NONE && cost != NodeCost.UNINITIALIZED) { - return true; - } - return false; - } - }, inlined); - } - - public static void printCompactTree(OutputStream out, Node node) { - printCompactTree(new PrintWriter(out), null, node, 1); + public static void printCompactTree(OutputStream out, OptimizedCallTarget target) { + printCompactTree(new PrintWriter(out), target); } - private static void printCompactTree(PrintWriter p, Node parent, Node node, int level) { - if (node == null) { - return; - } - for (int i = 0; i < level; i++) { - p.print(" "); - } - if (parent == null) { - p.println(node.getClass().getSimpleName()); - } else { - String fieldName = "unknownField"; - NodeField[] fields = NodeClass.get(parent.getClass()).getFields(); - for (NodeField field : fields) { - Object value = field.loadValue(parent); - if (value == node) { - fieldName = field.getName(); - break; - } else if (value instanceof Node[]) { - int index = 0; - for (Node arrayNode : (Node[]) value) { - if (arrayNode == node) { - fieldName = field.getName() + "[" + index + "]"; + public static void printCompactTree(PrintWriter p, OptimizedCallTarget target) { + target.accept(new CallTreeNodeVisitor() { + + public boolean visit(List decisionStack, Node node) { + if (node == null) { + return false; + } + int level = CallTreeNodeVisitor.getNodeDepth(decisionStack, node); + for (int i = 0; i < level; i++) { + p.print(" "); + } + Node parent = node.getParent(); + + if (parent == null) { + p.println(node.getClass().getSimpleName()); + } else { + String fieldName = "unknownField"; + NodeField[] fields = NodeClass.get(parent.getClass()).getFields(); + for (NodeField field : fields) { + Object value = field.loadValue(parent); + if (value == node) { + fieldName = field.getName(); break; + } else if (value instanceof Node[]) { + int index = 0; + for (Node arrayNode : (Node[]) value) { + if (arrayNode == node) { + fieldName = field.getName() + "[" + index + "]"; + break; + } + index++; + } } - index++; } + p.print(fieldName); + p.print(" = "); + p.println(node.getClass().getSimpleName()); } + p.flush(); + return false; } - p.print(fieldName); - p.print(" = "); - p.println(node.getClass().getSimpleName()); - } - for (Node child : node.getChildren()) { - printCompactTree(p, node, child, level + 1); - } - if (node instanceof OptimizedDirectCallNode) { - OptimizedDirectCallNode callNode = (OptimizedDirectCallNode) node; - if (callNode.isInlined()) { - printCompactTree(p, node, callNode.getCurrentRootNode(), level + 1); - } - } - p.flush(); + }, true); } } diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java Thu Oct 09 17:25:24 2014 +0200 @@ -37,7 +37,6 @@ private int callCount; private boolean inliningForced; - @CompilationFinal private boolean inlined; @CompilationFinal private OptimizedCallTarget splitCallTarget; @CompilationFinal private FrameAccess outsideFrameAccess = FrameAccess.NONE; @@ -57,14 +56,7 @@ if (CompilerDirectives.inInterpreter()) { onInterpreterCall(arguments); } - boolean isInlined; - if (TruffleCompilerOptions.TruffleContextSensitiveInlining.getValue()) { - /* Inlining done during partial evalulation. */ - isInlined = false; - } else { - isInlined = this.inlined; - } - Object result = callProxy(this, getCurrentCallTarget(), frame, arguments, isInlined, true); + Object result = callProxy(this, getCurrentCallTarget(), frame, arguments, true); if (CompilerDirectives.inInterpreter()) { afterInterpreterCall(result); @@ -74,17 +66,14 @@ private void afterInterpreterCall(Object result) { splittingStrategy.afterCall(result); - // propagateInliningInvalidations(); } - public static Object callProxy(MaterializedFrameNotify notify, CallTarget callTarget, VirtualFrame frame, Object[] arguments, boolean inlined, boolean direct) { + public static Object callProxy(MaterializedFrameNotify notify, CallTarget callTarget, VirtualFrame frame, Object[] arguments, boolean direct) { try { if (notify.getOutsideFrameAccess() != FrameAccess.NONE) { CompilerDirectives.materialize(frame); } - if (inlined) { - return ((OptimizedCallTarget) callTarget).callInlined(arguments); - } else if (direct) { + if (direct) { return ((OptimizedCallTarget) callTarget).callDirect(arguments); } else { return callTarget.call(arguments); @@ -95,13 +84,6 @@ } } - public void resetInlining() { - CompilerAsserts.neverPartOfCompilation(); - if (inlined && !inliningForced) { - inlined = false; - } - } - @Override public boolean isInlinable() { return true; @@ -157,7 +139,6 @@ getCurrentCallTarget().incrementKnownCallSites(); } splittingStrategy.beforeCall(arguments); - // propagateInliningInvalidations(); } /** Used by the splitting strategy to install new targets. */ @@ -184,23 +165,6 @@ } } - @SuppressWarnings("unused") - private void propagateInliningInvalidations() { - if (isInlined() && !getCurrentCallTarget().inliningPerformed) { - replace(this, "Propagate invalid inlining from " + getCurrentCallTarget().toString()); - } - } - - /* Called by the runtime system if this CallNode is really going to be inlined. */ - void inline() { - inlined = true; - } - - @Override - public boolean isInlined() { - return inlined; - } - @Override public boolean split() { splittingStrategy.forceSplitting(); diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedIndirectCallNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedIndirectCallNode.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedIndirectCallNode.java Thu Oct 09 17:25:24 2014 +0200 @@ -38,7 +38,7 @@ @Override public Object call(VirtualFrame frame, CallTarget target, Object[] arguments) { - return OptimizedDirectCallNode.callProxy(this, target, frame, arguments, false, false); + return OptimizedDirectCallNode.callProxy(this, target, frame, arguments, false); } @Override diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Thu Oct 09 17:25:24 2014 +0200 @@ -51,7 +51,6 @@ import com.oracle.graal.phases.common.inlining.info.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.phases.util.*; -import com.oracle.graal.truffle.ContextSensitiveInlining.InliningDecision; import com.oracle.graal.truffle.nodes.asserts.*; import com.oracle.graal.truffle.nodes.frame.*; import com.oracle.graal.truffle.nodes.frame.NewFrameNode.VirtualOnlyInstanceNode; @@ -83,7 +82,7 @@ this.callSiteProxyMethod = providers.getMetaAccess().lookupJavaMethod(GraalFrameInstance.CallNodeFrame.METHOD); } - public StructuredGraph createGraph(final OptimizedCallTarget callTarget, final Assumptions assumptions, ContextSensitiveInlining inlining) { + public StructuredGraph createGraph(final OptimizedCallTarget callTarget, final Assumptions assumptions) { if (TraceTruffleCompilationHistogram.getValue() || TraceTruffleCompilationDetails.getValue()) { constantReceivers = new HashSet<>(); } @@ -106,7 +105,15 @@ expandTree(graph, assumptions); - expandDirectCalls(graph, assumptions, inlining != null ? new TruffleInliningCache() : null, inlining); + TruffleInliningCache inliningCache = null; + if (TruffleFunctionInlining.getValue()) { + callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy())); + if (TruffleFunctionInliningCache.getValue()) { + inliningCache = new TruffleInliningCache(); + } + } + + expandDirectCalls(graph, assumptions, callTarget.getInlining(), inliningCache); if (Thread.currentThread().isInterrupted()) { return null; @@ -171,34 +178,6 @@ return graph; } - private void expandDirectCalls(StructuredGraph graph, Assumptions assumptions, TruffleInliningCache inliningCache, ContextSensitiveInlining inlining) { - if (inlining == null) { - return; - } - PhaseContext phaseContext = new PhaseContext(providers, assumptions); - TruffleExpansionLogger expansionLogger = new TruffleExpansionLogger(providers, graph); - - for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class).snapshot()) { - StructuredGraph inlineGraph = parseDirectCallGraph(phaseContext, assumptions, inliningCache, inlining, methodCallTargetNode); - - if (inlineGraph != null) { - expandTreeInline(graph, phaseContext, expansionLogger, methodCallTargetNode, inlineGraph); - } - } - // non inlined direct calls need to be expanded until TruffleCallBoundary. - expandTree(graph, assumptions); - assert noDirectCallsLeft(graph); - } - - private boolean noDirectCallsLeft(StructuredGraph graph) { - for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class).snapshot()) { - if (methodCallTargetNode.targetMethod().equals(callDirectMethod)) { - return false; - } - } - return true; - } - private void injectConstantCallTarget(final StructuredGraph graph, final OptimizedCallTarget constantCallTarget, PhaseContext baseContext) { ParameterNode thisNode = graph.getParameter(0); @@ -283,114 +262,16 @@ return changed; } - private StructuredGraph parseDirectCallGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInliningCache inliningCache, ContextSensitiveInlining inlining, - MethodCallTargetNode methodCallTargetNode) { - OptimizedDirectCallNode callNode = resolveConstantCallNode(methodCallTargetNode); - if (callNode == null) { - return null; - } - - InliningDecision decision = inlining.findByCall(callNode); - if (decision == null) { - if (TruffleCompilerOptions.PrintTrufflePerformanceWarnings.getValue()) { - Map properties = new LinkedHashMap<>(); - properties.put("callNode", callNode); - logPerformanceWarning("A direct call within the Truffle AST is not reachable anymore. Call node was not inlined.", properties); - } - return null; - } - - assert decision.getProfile().getCallNode() == callNode; - - OptimizedCallTarget currentTarget = decision.getProfile().getCallNode().getCurrentCallTarget(); - if (decision.getTarget() != currentTarget) { - if (TruffleCompilerOptions.PrintTrufflePerformanceWarnings.getValue()) { - Map properties = new LinkedHashMap<>(); - properties.put("originalTarget", decision.getTarget()); - properties.put("callNode", callNode); - logPerformanceWarning(String.format("CallTarget changed during compilation. Call node was not inlined."), properties); - } - return null; - } - - StructuredGraph graph; - if (decision.isInline()) { - if (inliningCache == null) { - graph = createInlineGraph(phaseContext, assumptions, null, decision); - } else { - graph = inliningCache.getCachedGraph(phaseContext, assumptions, decision); - } - decision.getProfile().setGraalDeepNodeCount(graph.getNodeCount()); - } else { - graph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, phaseContext); - } - - return graph; - } - - private StructuredGraph createInlineGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInliningCache cache, InliningDecision decision) { - try (Scope s = Debug.scope("GuestLanguageInlinedGraph", new DebugDumpScope(decision.getTarget().toString()))) { - OptimizedCallTarget target = decision.getTarget(); - StructuredGraph inlineGraph = truffleCache.createInlineGraph(target.toString()); - injectConstantCallTarget(inlineGraph, decision.getTarget(), phaseContext); - expandTree(inlineGraph, assumptions); - expandDirectCalls(inlineGraph, assumptions, cache, decision); - return inlineGraph; - } catch (Throwable e) { - throw Debug.handle(e); - } - } - - private OptimizedDirectCallNode resolveConstantCallNode(MethodCallTargetNode methodCallTargetNode) { - if (!methodCallTargetNode.targetMethod().equals(callDirectMethod)) { - return null; - } - - Invoke invoke = methodCallTargetNode.invoke(); - if (invoke == null) { - return null; - } - - FrameState directCallState = invoke.stateAfter(); - while (directCallState != null && directCallState.method() != callSiteProxyMethod) { - directCallState = directCallState.outerFrameState(); - } - - if (directCallState == null) { - // not a direct call. May be indirect call. - return null; - } - - if (directCallState.values().isEmpty()) { - throw new AssertionError(String.format("Frame state of method '%s' is invalid.", callDirectMethod.toString())); - } - - ValueNode node = directCallState.values().get(0); - if (!node.isConstant()) { - throw new AssertionError(String.format("Method argument for method '%s' is not constant.", callDirectMethod.toString())); - } - - Constant constantCallNode = node.asConstant(); - Object value = snippetReflection.asObject(constantCallNode); - - if (!(value instanceof OptimizedDirectCallNode)) { - // might be an indirect call. - return null; - } - - return (OptimizedDirectCallNode) value; - } - private void expandTreeInline(StructuredGraph graph, PhaseContext phaseContext, TruffleExpansionLogger expansionLogger, MethodCallTargetNode methodCallTargetNode, StructuredGraph inlineGraph) { try (Indent indent = Debug.logAndIndent("expand graph %s", methodCallTargetNode.targetMethod())) { int nodeCountBefore = graph.getNodeCount(); - if (TraceTruffleExpansion.getValue()) { + if (TraceTruffleExpansion.getValue() && expansionLogger != null) { expansionLogger.preExpand(methodCallTargetNode, inlineGraph); } List canonicalizedNodes = methodCallTargetNode.invoke().asNode().usages().snapshot(); Map inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false, canonicalizedNodes); - if (TraceTruffleExpansion.getValue()) { + if (TraceTruffleExpansion.getValue() && expansionLogger != null) { expansionLogger.postExpand(inlined); } if (Debug.isDumpEnabled()) { @@ -454,6 +335,132 @@ } } + private void expandDirectCalls(StructuredGraph graph, Assumptions assumptions, TruffleInlining inlining, TruffleInliningCache inliningCache) { + PhaseContext phaseContext = new PhaseContext(providers, assumptions); + + for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class).snapshot()) { + StructuredGraph inlineGraph = parseDirectCallGraph(phaseContext, assumptions, inlining, inliningCache, methodCallTargetNode); + + if (inlineGraph != null) { + expandTreeInline(graph, phaseContext, null, methodCallTargetNode, inlineGraph); + } + } + // non inlined direct calls need to be expanded until TruffleCallBoundary. + expandTree(graph, assumptions); + assert noDirectCallsLeft(graph); + } + + private boolean noDirectCallsLeft(StructuredGraph graph) { + for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class).snapshot()) { + if (methodCallTargetNode.targetMethod().equals(callDirectMethod)) { + return false; + } + } + return true; + } + + private StructuredGraph parseDirectCallGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInlining inlining, TruffleInliningCache inliningCache, + MethodCallTargetNode methodCallTargetNode) { + OptimizedDirectCallNode callNode = resolveConstantCallNode(methodCallTargetNode); + if (callNode == null) { + return null; + } + + TruffleInliningDecision decision = inlining.findByCall(callNode); + boolean inline; + if (decision == null) { + if (TruffleCompilerOptions.PrintTrufflePerformanceWarnings.getValue()) { + Map properties = new LinkedHashMap<>(); + properties.put("callNode", callNode); + logPerformanceWarning("A direct call within the Truffle AST is not reachable anymore. Call node could not be inlined.", properties); + } + inline = false; + } else { + inline = decision.isInline(); + } + + assert decision.getProfile().getCallNode() == callNode; + + OptimizedCallTarget currentTarget = decision.getProfile().getCallNode().getCurrentCallTarget(); + if (decision.getTarget() != currentTarget) { + if (TruffleCompilerOptions.PrintTrufflePerformanceWarnings.getValue()) { + Map properties = new LinkedHashMap<>(); + properties.put("originalTarget", decision.getTarget()); + properties.put("callNode", callNode); + logPerformanceWarning(String.format("CallTarget changed during compilation. Call node could not be inlined."), properties); + } + inline = false; + } + + StructuredGraph graph; + if (inline) { + if (inliningCache == null) { + graph = createInlineGraph(phaseContext, assumptions, null, decision); + } else { + graph = inliningCache.getCachedGraph(phaseContext, assumptions, decision); + } + decision.getProfile().setGraalDeepNodeCount(graph.getNodeCount()); + } else { + // we continue expansion of callDirect until we reach the callBoundary. + graph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), assumptions, phaseContext); + } + + return graph; + } + + private OptimizedDirectCallNode resolveConstantCallNode(MethodCallTargetNode methodCallTargetNode) { + if (!methodCallTargetNode.targetMethod().equals(callDirectMethod)) { + return null; + } + + Invoke invoke = methodCallTargetNode.invoke(); + if (invoke == null) { + return null; + } + + FrameState directCallState = invoke.stateAfter(); + while (directCallState != null && directCallState.method() != callSiteProxyMethod) { + directCallState = directCallState.outerFrameState(); + } + + if (directCallState == null) { + // not a direct call. May be indirect call. + return null; + } + + if (directCallState.values().isEmpty()) { + throw new AssertionError(String.format("Frame state of method '%s' is invalid.", callDirectMethod.toString())); + } + + ValueNode node = directCallState.values().get(0); + if (!node.isConstant()) { + throw new AssertionError(String.format("Method argument for method '%s' is not constant.", callDirectMethod.toString())); + } + + Constant constantCallNode = node.asConstant(); + Object value = snippetReflection.asObject(constantCallNode); + + if (!(value instanceof OptimizedDirectCallNode)) { + // might be an indirect call. + return null; + } + + return (OptimizedDirectCallNode) value; + } + + private StructuredGraph createInlineGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInliningCache cache, TruffleInliningDecision decision) { + try (Scope s = Debug.scope("GuestLanguageInlinedGraph", new DebugDumpScope(decision.getTarget().toString()))) { + OptimizedCallTarget target = decision.getTarget(); + StructuredGraph inlineGraph = truffleCache.createInlineGraph(target.toString()); + injectConstantCallTarget(inlineGraph, decision.getTarget(), phaseContext); + expandTree(inlineGraph, assumptions); + expandDirectCalls(inlineGraph, assumptions, decision, cache); + return inlineGraph; + } catch (Throwable e) { + throw Debug.handle(e); + } + } + private static List innerLoopsFirst(Collection loops) { ArrayList sortedLoops = new ArrayList<>(loops); Collections.sort(sortedLoops, new Comparator() { @@ -474,7 +481,7 @@ this.cache = new HashMap<>(); } - public StructuredGraph getCachedGraph(PhaseContext phaseContext, Assumptions assumptions, InliningDecision decision) { + public StructuredGraph getCachedGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInliningDecision decision) { CacheKey cacheKey = new CacheKey(decision); StructuredGraph inlineGraph = cache.get(cacheKey); if (inlineGraph == null) { @@ -486,9 +493,9 @@ private final class CacheKey { - public final InliningDecision decision; + public final TruffleInliningDecision decision; - public CacheKey(InliningDecision decision) { + public CacheKey(TruffleInliningDecision decision) { this.decision = decision; /* * If decision.isInline() is not true CacheKey#hashCode does not match diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Thu Oct 09 17:25:24 2014 +0200 @@ -108,22 +108,16 @@ public void compileMethodImpl(final OptimizedCallTarget compilable) { final StructuredGraph graph; - if (TraceTruffleCompilation.getValue() || TraceTruffleCompilationAST.getValue()) { + if (TraceTruffleCompilation.getValue()) { OptimizedCallTargetLog.logOptimizingStart(compilable); - if (TraceTruffleCompilationAST.getValue()) { - OptimizedCallUtils.printCompactTree(OptimizedCallTarget.OUT, compilable.getRootNode()); - } - } - if (TraceTruffleCompilationCallTree.getValue()) { - OptimizedCallTargetLog.log(0, "opt call tree", compilable.toString(), compilable.getDebugProperties()); - OptimizedCallTargetLog.logTruffleCalls(compilable); + } long timeCompilationStarted = System.nanoTime(); Assumptions assumptions = new Assumptions(true); - ContextSensitiveInlining inlining = TruffleCompilerOptions.TruffleContextSensitiveInlining.getValue() ? new ContextSensitiveInlining(compilable, new DefaultInliningPolicy()) : null; + try (TimerCloseable a = PartialEvaluationTime.start(); Closeable c = PartialEvaluationMemUse.start()) { - graph = partialEvaluator.createGraph(compilable, assumptions, inlining); + graph = partialEvaluator.createGraph(compilable, assumptions); } if (Thread.currentThread().isInterrupted()) { @@ -136,21 +130,37 @@ long timeCompilationFinished = System.nanoTime(); int nodeCountLowered = graph.getNodeCount(); - compilable.setInliningDecision(inlining); - - if (TraceTruffleInlining.getValue() && inlining != null) { - OptimizedCallTargetLog.logInliningDecision(compilable); - } if (TraceTruffleCompilation.getValue()) { printTruffleCompilation(compilable, timeCompilationStarted, timePartialEvaluationFinished, nodeCountPartialEval, compilationResult, timeCompilationFinished, nodeCountLowered); } + if (TraceTruffleCompilationAST.getValue()) { + OptimizedCallUtils.printCompactTree(OptimizedCallTarget.OUT, compilable); + } + if (TraceTruffleCompilationCallTree.getValue()) { + OptimizedCallTargetLog.log(0, "opt call tree", compilable.toString(), compilable.getDebugProperties()); + OptimizedCallTargetLog.logTruffleCallTree(compilable); + } + if (TraceTruffleInlining.getValue()) { + OptimizedCallTargetLog.logInliningDecision(compilable); + } } private static void printTruffleCompilation(final OptimizedCallTarget compilable, long timeCompilationStarted, long timePartialEvaluationFinished, int nodeCountPartialEval, CompilationResult compilationResult, long timeCompilationFinished, int nodeCountLowered) { - int calls = OptimizedCallUtils.countCalls(compilable); - int inlinedCalls = OptimizedCallUtils.countCallsInlined(compilable); + + TruffleInlining inlining = compilable.getInlining(); + + int calls; + int inlinedCalls; + if (inlining == null) { + calls = (int) compilable.nodeStream(false).filter(node -> (node instanceof OptimizedDirectCallNode)).count(); + inlinedCalls = 0; + } else { + calls = inlining.countCalls(); + inlinedCalls = inlining.countInlinedCalls(); + } + int dispatchedCalls = calls - inlinedCalls; Map properties = new LinkedHashMap<>(); OptimizedCallTargetLog.addASTSizeProperty(compilable, properties); @@ -158,7 +168,7 @@ (timeCompilationFinished - timeCompilationStarted) / 1e6, // (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, // (timeCompilationFinished - timePartialEvaluationFinished) / 1e6)); - properties.put("CallNodes", String.format("I %5d/D %5d", inlinedCalls, dispatchedCalls)); + properties.put("DirectCallNodes", String.format("I %4d/D %4d", inlinedCalls, dispatchedCalls)); properties.put("GraalNodes", String.format("%5d/%5d", nodeCountPartialEval, nodeCountLowered)); properties.put("CodeSize", compilationResult.getTargetCodeSize()); properties.put("Source", formatSourceSection(compilable.getRootNode().getSourceSection())); diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Thu Oct 09 17:25:24 2014 +0200 @@ -53,20 +53,12 @@ public static final OptionValue TruffleReplaceReprofileCount = new OptionValue<>(10); @Option(help = "Enable automatic inlining of call targets") public static final OptionValue TruffleFunctionInlining = new OptionValue<>(true); - @Option(help = "Experimental: Enable context senstive inlining decisions.") - public static final StableOptionValue TruffleContextSensitiveInlining = new StableOptionValue<>(false); - @Option(help = "Experimental: Enable an expansion cache per CallTarget. Only functionable with TruffleContextSensitiveInlining enabled.") - public static final OptionValue TruffleCallTargetExpansionCache = new OptionValue<>(true); + @Option(help = "Enable an expansion cache per CallTarget. Only functionable with TruffleContextSensitiveInlining enabled.") + public static final OptionValue TruffleFunctionInliningCache = new OptionValue<>(true); @Option(help = "Maximum number of Graal IR nodes during partial evaluation") public static final OptionValue TruffleGraphMaxNodes = new OptionValue<>(200000); @Option(help = "Stop inlining if caller's cumulative tree size would exceed this limit") public static final OptionValue TruffleInliningMaxCallerSize = new OptionValue<>(2250); - @Option(help = "Skip inlining candidate if its tree size exceeds this limit") - public static final OptionValue TruffleInliningMaxCalleeSize = new OptionValue<>(500); - @Option(help = "Call frequency relative to call target") - public static final OptionValue TruffleInliningMinFrequency = new OptionValue<>(0.3); - @Option(help = "Allow inlining of less hot candidates if tree size is small") - public static final OptionValue TruffleInliningTrivialSize = new OptionValue<>(10); @Option(help = "Defines the number of graal nodes that triggers a performance warning.") public static final OptionValue TrufflePerformanceWarningGraalNodeCount = new OptionValue<>(1000); diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java Thu Oct 09 17:25:24 2014 +0200 @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2014, 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.graal.truffle; + +import java.util.*; +import java.util.stream.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.Node; + +public class TruffleInlining implements Iterable { + + private final List callSites; + + TruffleInlining(List callSites) { + this.callSites = callSites; + } + + public TruffleInlining(OptimizedCallTarget sourceTarget, TruffleInliningPolicy policy) { + this(createDecisions(sourceTarget, policy)); + } + + private static List createDecisions(OptimizedCallTarget sourceTarget, TruffleInliningPolicy policy) { + int nodeCount = OptimizedCallUtils.countNonTrivialNodes(sourceTarget, false); + List exploredCallSites = exploreCallSites(new ArrayList<>(Arrays.asList(sourceTarget)), nodeCount, policy); + return decideInlining(exploredCallSites, policy, nodeCount); + } + + private static List exploreCallSites(List stack, int callStackNodeCount, TruffleInliningPolicy policy) { + List exploredCallSites = new ArrayList<>(); + OptimizedCallTarget parentTarget = stack.get(stack.size() - 1); + for (OptimizedDirectCallNode callNode : parentTarget.getCallNodes()) { + OptimizedCallTarget currentTarget = callNode.getCurrentCallTarget(); + stack.add(currentTarget); // push + exploredCallSites.add(exploreCallSite(stack, callStackNodeCount, policy, callNode)); + stack.remove(stack.size() - 1); // pop + } + return exploredCallSites; + } + + private static TruffleInliningDecision exploreCallSite(List callStack, int callStackNodeCount, TruffleInliningPolicy policy, OptimizedDirectCallNode callNode) { + OptimizedCallTarget parentTarget = callStack.get(callStack.size() - 2); + OptimizedCallTarget currentTarget = callStack.get(callStack.size() - 1); + + List childCallSites = Collections.emptyList(); + double frequency = calculateFrequency(parentTarget, callNode); + int nodeCount = OptimizedCallUtils.countNonTrivialNodes(callNode.getCurrentCallTarget(), false); + + boolean recursive = isRecursiveStack(callStack); + int deepNodeCount = nodeCount; + if (!recursive && callStack.size() < 15) { + /* + * We make a preliminary optimistic inlining decision with best possible characteristics + * to avoid the exploration of unnecessary pathes in the inlining tree. + */ + if (policy.isAllowed(new TruffleInliningProfile(callNode, nodeCount, nodeCount, frequency, recursive), callStackNodeCount)) { + List exploredCallSites = exploreCallSites(callStack, callStackNodeCount + nodeCount, policy); + childCallSites = decideInlining(exploredCallSites, policy, nodeCount); + for (TruffleInliningDecision childCallSite : childCallSites) { + if (childCallSite.isInline()) { + deepNodeCount += childCallSite.getProfile().getDeepNodeCount(); + } else { + /* we don't need those anymore. */ + childCallSite.getCallSites().clear(); + } + } + } + } + + TruffleInliningProfile profile = new TruffleInliningProfile(callNode, nodeCount, deepNodeCount, frequency, recursive); + profile.setScore(policy.calculateScore(profile)); + return new TruffleInliningDecision(currentTarget, profile, childCallSites); + } + + private static double calculateFrequency(OptimizedCallTarget target, OptimizedDirectCallNode ocn) { + return (double) Math.max(1, ocn.getCallCount()) / (double) Math.max(1, target.getCompilationProfile().getCallCount()); + } + + private static boolean isRecursiveStack(List stack) { + OptimizedCallTarget top = stack.get(stack.size() - 1); + for (int i = 0; i < stack.size() - 1; i++) { + if (stack.get(i) == top) { + return true; + } + } + return false; + } + + private static List decideInlining(List callSites, TruffleInliningPolicy policy, int nodeCount) { + int deepNodeCount = nodeCount; + int index = 0; + for (TruffleInliningDecision callSite : callSites.stream().sorted().collect(Collectors.toList())) { + TruffleInliningProfile profile = callSite.getProfile(); + profile.setQueryIndex(index++); + if (policy.isAllowed(profile, deepNodeCount)) { + callSite.setInline(true); + deepNodeCount += profile.getDeepNodeCount(); + } + } + return callSites; + } + + public int getInlinedNodeCount() { + return getCallSites().stream().filter(callSite -> callSite.isInline()).mapToInt(callSite -> callSite.getProfile().getDeepNodeCount()).sum(); + } + + public int countCalls() { + return getCallSites().stream().mapToInt(callSite -> callSite.isInline() ? callSite.countCalls() + 1 : 1).sum(); + } + + public int countInlinedCalls() { + return getCallSites().stream().filter(TruffleInliningDecision::isInline).mapToInt(callSite -> callSite.countInlinedCalls() + 1).sum(); + } + + public final List getCallSites() { + return callSites; + } + + public Iterator iterator() { + return callSites.iterator(); + } + + public TruffleInliningDecision findByCall(OptimizedDirectCallNode callNode) { + return getCallSites().stream().filter(c -> c.getProfile().getCallNode() == callNode).findFirst().orElse(null); + } + + /** + * Visits all nodes of the {@link CallTarget} and all of its inlined calls. + */ + public void accept(OptimizedCallTarget target, NodeVisitor visitor) { + target.getRootNode().accept(new CallTreeNodeVisitorImpl(target, visitor)); + } + + /** + * Creates an iterator for all nodes of the {@link CallTarget} and all of its inlined calls. + */ + public Iterator makeNodeIterator(OptimizedCallTarget target) { + return new CallTreeNodeIterator(target); + } + + /** + * This visitor extends the {@link NodeVisitor} interface to be usable for traversing the full + * call tree. + */ + public interface CallTreeNodeVisitor extends NodeVisitor { + + public boolean visit(List decisionStack, Node node); + + public default boolean visit(Node node) { + return visit(null, node); + } + + static int getNodeDepth(List decisionStack, Node node) { + int depth = calculateNodeDepth(node); + for (int i = decisionStack.size() - 1; i > 0; i--) { + TruffleInliningDecision decision = (TruffleInliningDecision) decisionStack.get(i); + depth += calculateNodeDepth(decision.getProfile().getCallNode()); + } + return depth; + } + + static int calculateNodeDepth(Node node) { + int depth = 0; + Node traverseNode = node; + while (traverseNode != null) { + depth++; + traverseNode = traverseNode.getParent(); + } + return depth; + } + + } + + /** + * This visitor wraps an existing {@link NodeVisitor} or {@link CallTreeNodeVisitor} and + * traverses the full Truffle tree including inlined call sites. + */ + private final static class CallTreeNodeVisitorImpl implements NodeVisitor { + + protected final List stack = new ArrayList<>(); + private final NodeVisitor visitor; + private boolean continueTraverse = true; + + public CallTreeNodeVisitorImpl(OptimizedCallTarget target, NodeVisitor visitor) { + stack.add(target.getInlining()); + this.visitor = visitor; + } + + public final boolean visit(Node node) { + if (node instanceof OptimizedDirectCallNode) { + OptimizedDirectCallNode callNode = (OptimizedDirectCallNode) node; + TruffleInlining inlining = stack.get(stack.size() - 1); + if (inlining != null) { + TruffleInliningDecision childInlining = inlining.findByCall(callNode); + if (childInlining != null) { + stack.add(childInlining); + continueTraverse = visitNode(node); + if (continueTraverse) { + childInlining.getTarget().getRootNode().accept(this); + } + stack.remove(stack.size() - 1); + } + } + return continueTraverse; + } else { + continueTraverse = visitNode(node); + return continueTraverse; + } + } + + private boolean visitNode(Node node) { + if (visitor instanceof CallTreeNodeVisitor) { + return ((CallTreeNodeVisitor) visitor).visit(stack, node); + } else { + return visitor.visit(node); + } + } + } + + private static final class CallTreeNodeIterator implements Iterator { + + private List inliningDecisionStack = new ArrayList<>(); + private List> iteratorStack = new ArrayList<>(); + + public CallTreeNodeIterator(OptimizedCallTarget target) { + inliningDecisionStack.add(target.getInlining()); + iteratorStack.add(NodeUtil.makeRecursiveIterator(target.getRootNode())); + } + + public boolean hasNext() { + return peekIterator() != null; + } + + public Node next() { + Iterator iterator = peekIterator(); + if (iterator == null) { + throw new NoSuchElementException(); + } + + Node node = iterator.next(); + if (node instanceof OptimizedDirectCallNode) { + visitInlinedCall(node); + } + return node; + } + + private void visitInlinedCall(Node node) { + TruffleInlining currentDecision = inliningDecisionStack.get(inliningDecisionStack.size() - 1); + if (currentDecision == null) { + return; + } + TruffleInliningDecision decision = currentDecision.findByCall((OptimizedDirectCallNode) node); + if (decision.isInline()) { + inliningDecisionStack.add(decision); + iteratorStack.add(NodeUtil.makeRecursiveIterator(decision.getTarget().getRootNode())); + } + } + + private Iterator peekIterator() { + int tos = iteratorStack.size() - 1; + while (tos >= 0) { + Iterator iterable = iteratorStack.get(tos); + if (iterable.hasNext()) { + return iterable; + } else { + iteratorStack.remove(--tos); + inliningDecisionStack.remove(--tos); + } + } + return null; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + } + +} diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningDecision.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningDecision.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningDecision.java Thu Oct 09 17:25:24 2014 +0200 @@ -24,49 +24,61 @@ import java.util.*; -public final class TruffleInliningDecision implements Iterable { +public final class TruffleInliningDecision extends TruffleInlining implements Comparable { - private final OptimizedCallTarget callTarget; - private final Map profiles; - private final Set inlined; - private final int nodeCount; + private final OptimizedCallTarget target; + private final TruffleInliningProfile profile; + private boolean inline; - public TruffleInliningDecision(OptimizedCallTarget callTarget, List profiles, Set inlined, int nodeCount) { - this.callTarget = callTarget; - this.profiles = new HashMap<>(); - for (TruffleInliningProfile profile : profiles) { - this.profiles.put(profile.getCallNode(), profile); - } - this.nodeCount = nodeCount; - this.inlined = inlined; + public TruffleInliningDecision(OptimizedCallTarget target, TruffleInliningProfile profile, List children) { + super(children); + this.target = target; + this.profile = profile; + } + + public OptimizedCallTarget getTarget() { + return target; + } + + void setInline(boolean inline) { + this.inline = inline; + } + + public boolean isInline() { + return inline; } - public Map getProfiles() { - return profiles; + public TruffleInliningProfile getProfile() { + return profile; } - public int getNodeCount() { - return nodeCount; + public int compareTo(TruffleInliningDecision o) { + return Double.compare(o.getProfile().getScore(), getProfile().getScore()); } - public OptimizedCallTarget getCallTarget() { - return callTarget; - } - - public boolean isInlined(OptimizedDirectCallNode path) { - return inlined.contains(profiles.get(path)); - } - - public int size() { - return inlined.size(); - } - - public Iterator iterator() { - return Collections.unmodifiableSet(inlined).iterator(); + public boolean isSameAs(TruffleInliningDecision other) { + if (getTarget() != other.getTarget()) { + return false; + } else if (isInline() != other.isInline()) { + return false; + } else if (!isInline()) { + assert !other.isInline(); + return true; + } else { + Iterator i1 = iterator(); + Iterator i2 = other.iterator(); + while (i1.hasNext() && i2.hasNext()) { + if (!i1.next().isSameAs(i2.next())) { + return false; + } + } + return !i1.hasNext() && !i2.hasNext(); + } } @Override public String toString() { - return inlined.toString(); + return String.format("TruffleInliningDecision(callNode=%s, inline=%b)", profile.getCallNode(), inline); } + } diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java Thu Oct 09 17:25:18 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * 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 com.oracle.graal.truffle; - -import java.util.*; - -import com.oracle.truffle.api.nodes.*; - -public final class TruffleInliningHandler { - - private static final int MAXIMUM_RECURSIVE_DEPTH = 15; - private static final ProfileScoreComparator INLINING_SCORE = new ProfileScoreComparator(); - private final TruffleInliningPolicy policy; - private final Map resultCache; - - public TruffleInliningHandler(TruffleInliningPolicy policy) { - this.policy = policy; - this.resultCache = new HashMap<>(); - } - - public TruffleInliningDecision decideInlining(OptimizedCallTarget target, int depth) { - if (resultCache.containsKey(target)) { - return resultCache.get(target); - } - resultCache.put(target, null); // important for recursion detection - TruffleInliningDecision result = createInliningDecision(target, depth); - resultCache.put(target, result); - return result; - } - - private TruffleInliningDecision createInliningDecision(OptimizedCallTarget target, int depth) { - List profiles = createProfiles(target, depth); - Set inlined = new HashSet<>(); - Collections.sort(profiles, INLINING_SCORE); - int deepNodeCount = OptimizedCallUtils.countNonTrivialNodes(target, true); - int index = 0; - - for (TruffleInliningProfile profile : profiles) { - profile.setQueryIndex(index++); - if (policy.isAllowed(profile, deepNodeCount)) { - inlined.add(profile); - deepNodeCount += profile.getDeepNodeCount(); - } - } - - return new TruffleInliningDecision(target, profiles, inlined, deepNodeCount); - } - - private List createProfiles(final OptimizedCallTarget target, final int depth) { - final List profiles = new ArrayList<>(); - target.getRootNode().accept(new NodeVisitor() { - public boolean visit(Node node) { - if (node instanceof OptimizedDirectCallNode) { - profiles.add(createProfile(target, (OptimizedDirectCallNode) node, depth)); - } - return true; - } - }); - return profiles; - } - - public TruffleInliningProfile createProfile(OptimizedCallTarget parentTarget, OptimizedDirectCallNode ocn, int depth) { - OptimizedCallTarget target = ocn.getCurrentCallTarget(); - - int nodeCount = OptimizedCallUtils.countNonTrivialNodes(target, false); - double frequency = calculateFrequency(parentTarget, ocn); - - int deepNodeCount; - TruffleInliningDecision recursiveResult; - boolean recursiveCall = false; - if (target.inliningPerformed || depth > MAXIMUM_RECURSIVE_DEPTH) { - deepNodeCount = OptimizedCallUtils.countNonTrivialNodes(target, true); - recursiveResult = null; - } else { - recursiveResult = decideInlining(ocn.getCurrentCallTarget(), depth + 1); - if (recursiveResult == null) { - recursiveCall = true; - deepNodeCount = Integer.MAX_VALUE; - } else { - deepNodeCount = recursiveResult.getNodeCount(); - } - } - - TruffleInliningProfile profile = new TruffleInliningProfile(ocn, nodeCount, deepNodeCount, frequency, recursiveCall, recursiveResult); - profile.setScore(policy.calculateScore(profile)); - return profile; - } - - public TruffleInliningPolicy getPolicy() { - return policy; - } - - public static double calculateFrequency(OptimizedCallTarget target, OptimizedDirectCallNode ocn) { - return (double) Math.max(1, ocn.getCallCount()) / (double) Math.max(1, target.getCompilationProfile().getCallCount()); - } - - private final static class ProfileScoreComparator implements Comparator { - - public int compare(TruffleInliningProfile o1, TruffleInliningProfile o2) { - return Double.compare(o2.getScore(), o1.getScore()); - } - - } -} diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java Thu Oct 09 17:25:24 2014 +0200 @@ -31,20 +31,18 @@ private final int deepNodeCount; private final double frequency; private final boolean recursiveCall; - private final TruffleInliningDecision recursiveResult; private int graalDeepNodeCount = -1; private String failedReason; private int queryIndex = -1; private double score; - public TruffleInliningProfile(OptimizedDirectCallNode callNode, int nodeCount, int deepNodeCount, double frequency, boolean recursiveCall, TruffleInliningDecision recursiveResult) { + public TruffleInliningProfile(OptimizedDirectCallNode callNode, int nodeCount, int deepNodeCount, double frequency, boolean recursiveCall) { this.callNode = callNode; this.nodeCount = nodeCount; this.deepNodeCount = deepNodeCount; this.frequency = frequency; this.recursiveCall = recursiveCall; - this.recursiveResult = recursiveResult; } public boolean isRecursiveCall() { @@ -63,10 +61,6 @@ return nodeCount; } - public TruffleInliningDecision getRecursiveResult() { - return recursiveResult; - } - public void setScore(double score) { this.score = score; } diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDirectCallNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDirectCallNode.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDirectCallNode.java Thu Oct 09 17:25:24 2014 +0200 @@ -89,11 +89,6 @@ } @Override - public boolean isInlined() { - return false; - } - - @Override public boolean isSplittable() { return false; } diff -r 5787218bad91 -r e3dd05527c2f graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/DirectCallNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/DirectCallNode.java Thu Oct 09 17:25:18 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/DirectCallNode.java Thu Oct 09 17:25:24 2014 +0200 @@ -101,8 +101,14 @@ * {@link DirectCallNode} is really going to be inlined. This depends on whether or not the * runtime system supports inlining. The runtime system may also decide to not inline calls * which were forced to inline. + * + * @deprecated we do not expose this information any longer. returns always false. */ - public abstract boolean isInlined(); + @SuppressWarnings("static-method") + @Deprecated + public final boolean isInlined() { + return false; + } /** * Returns true if this {@link DirectCallNode} can be split. A