# HG changeset patch # User Doug Simon # Date 1370618881 -7200 # Node ID 63bae87147dfe815d9bbdb95e94f933981a940fe # Parent 4f5e5bb0318457f009021be970b1f0a0fe9ebdf9# Parent 78a1232be4184532139abbb9bca213e9abe6c23e Merge. diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DeoptimizationAction.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DeoptimizationAction.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DeoptimizationAction.java Fri Jun 07 17:28:01 2013 +0200 @@ -32,28 +32,39 @@ * it's highly likely nothing will change the likelihood of the deoptimization happening again. * For example, a compiled array allocation where the size is negative. */ - None, + None(false), /** * Do not invalidate the machine code, but schedule a recompilation if this deoptimization is * triggered too often. */ - RecompileIfTooManyDeopts, + RecompileIfTooManyDeopts(true), /** * Invalidate the machine code and reset the profiling information. */ - InvalidateReprofile, + InvalidateReprofile(true), /** * Invalidate the machine code and immediately schedule a recompilation. This is typically used * when deoptimizing to resolve an unresolved symbol in which case extra profiling is not * required to determine that the deoptimization will not re-occur. */ - InvalidateRecompile, + InvalidateRecompile(true), /** * Invalidate the machine code and stop compiling the outermost method of this compilation. */ - InvalidateStopCompiling; + InvalidateStopCompiling(true); + + private final boolean invalidatesCompilation; + + private DeoptimizationAction(boolean invalidatesCompilation) { + this.invalidatesCompilation = invalidatesCompilation; + } + + public boolean doesInvalidateCompilation() { + return invalidatesCompilation; + } + } diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java Fri Jun 07 17:28:01 2013 +0200 @@ -25,10 +25,14 @@ import java.io.*; /** - * This profile object represents a certain set of profiling information at a specific BCI. The - * precision of the supplied values may vary, but a runtime that provides this information should be - * aware that it will be used to guide performance-critical decisions like speculative inlining, - * etc. + * This object holds probability information for a set of items that were profiled at a specific + * BCI. The precision of the supplied values may vary, but a runtime that provides this information + * should be aware that it will be used to guide performance-critical decisions like speculative + * inlining, etc. + * + * @param a subclass of AbstractProfiledItem + * @param the class of the items that are profiled at the specific BCI and for which + * probabilities are stored. E.g., a ResolvedJavaType or a ResolvedJavaMethod. */ public abstract class AbstractJavaProfile, U> implements Serializable { diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DefaultProfilingInfo.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DefaultProfilingInfo.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DefaultProfilingInfo.java Fri Jun 07 17:28:01 2013 +0200 @@ -87,6 +87,11 @@ } @Override + public boolean isMature() { + return false; + } + + @Override public String toString() { return "BaseProfilingInfo<" + MetaUtil.profileToString(this, null, "; ") + ">"; } diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java Fri Jun 07 17:28:01 2013 +0200 @@ -112,4 +112,12 @@ */ int getDeoptimizationCount(DeoptimizationReason reason); + /** + * Returns true if the profiling information can be assumed as sufficiently accurate. + * + * @return true if the profiling information was recorded often enough mature enough, false + * otherwise. + */ + boolean isMature(); + } diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ProfilingInfoTest.java Fri Jun 07 17:28:01 2013 +0200 @@ -128,7 +128,11 @@ } public static Serializable checkCastSnippet(Object obj) { - return (Serializable) obj; + try { + return (Serializable) obj; + } catch (ClassCastException e) { + return null; + } } @Test @@ -250,19 +254,30 @@ @Test public void testNullSeen() { - ProfilingInfo info = profile("instanceOfSnippet", 1); + testNullSeen("instanceOfSnippet"); + testNullSeen("checkCastSnippet"); + } + + private void testNullSeen(String snippet) { + ProfilingInfo info = profile(snippet, 1); Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); - continueProfiling("instanceOfSnippet", "ABC"); + continueProfiling(snippet, "ABC"); Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); - continueProfiling("instanceOfSnippet", (Object) null); + continueProfiling(snippet, new Object()); + Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); + + continueProfiling(snippet, (Object) null); Assert.assertEquals(TriState.TRUE, info.getNullSeen(1)); - continueProfiling("instanceOfSnippet", 0.0); + continueProfiling(snippet, 0.0); Assert.assertEquals(TriState.TRUE, info.getNullSeen(1)); - resetProfile("instanceOfSnippet"); + continueProfiling(snippet, new Object()); + Assert.assertEquals(TriState.TRUE, info.getNullSeen(1)); + + resetProfile(snippet); Assert.assertEquals(TriState.FALSE, info.getNullSeen(1)); } diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Fri Jun 07 17:28:01 2013 +0200 @@ -384,6 +384,8 @@ public int typeProfileWidth; public int methodProfileWidth; + public int interpreterProfilingThreshold; + public long inlineCacheMissStub; public long handleDeoptStub; public long uncommonTrapStub; diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphCache.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphCache.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphCache.java Fri Jun 07 17:28:01 2013 +0200 @@ -127,13 +127,15 @@ } @Override - public void put(StructuredGraph graph) { + public void put(StructuredGraph graph, boolean hasMatureProfilingInfo) { assert graph.method() != null; - cachedGraphIds.put(graph.graphId(), new WeakReference<>(graph.method())); - graph.method().getCompilerStorage().put(this, graph); + if (hasMatureProfilingInfo) { + cachedGraphIds.put(graph.graphId(), new WeakReference<>(graph.method())); + graph.method().getCompilerStorage().put(this, graph); - if (PrintGraphCache.getValue()) { - putCounter++; + if (PrintGraphCache.getValue()) { + putCounter++; + } } } diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Fri Jun 07 17:28:01 2013 +0200 @@ -24,7 +24,6 @@ import static com.oracle.graal.graph.UnsafeAccess.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; -import static com.oracle.graal.phases.GraalOptions.*; import java.util.*; @@ -376,7 +375,7 @@ protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position); private static JavaTypeProfile createTypeProfile(TriState nullSeen, ResolvedJavaType[] types, long[] counts, long totalCount, int entries) { - if (entries <= 0 || totalCount < MatureExecutionsTypeProfile.getValue()) { + if (entries <= 0 || totalCount <= 0) { return null; } @@ -484,7 +483,7 @@ } private static JavaMethodProfile createMethodProfile(ResolvedJavaMethod[] methods, long[] counts, long totalCount, int entries) { - if (entries <= 0 || totalCount < MatureExecutionsTypeProfile.getValue()) { + if (entries <= 0 || totalCount <= 0) { return null; } @@ -540,11 +539,7 @@ long notTakenCount = data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); long total = takenCount + notTakenCount; - if (total < MatureExecutionsBranch.getValue()) { - return -1; - } else { - return takenCount / (double) total; - } + return total <= 0 ? -1 : takenCount / (double) total; } @Override @@ -607,7 +602,7 @@ result[i - 1] = count; } - if (totalCount < MatureExecutionsPerSwitchCase.getValue() * length) { + if (totalCount <= 0) { return null; } else { for (int i = 0; i < length; i++) { diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProfilingInfo.java Fri Jun 07 17:28:01 2013 +0200 @@ -22,32 +22,36 @@ */ package com.oracle.graal.hotspot.meta; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.phases.*; public final class HotSpotProfilingInfo extends CompilerObject implements ProfilingInfo { private static final long serialVersionUID = -8307682725047864875L; private static final DebugMetric metricInsufficentSpace = Debug.metric("InsufficientSpaceForProfilingData"); + private final HotSpotMethodData methodData; + private final HotSpotResolvedJavaMethod method; + private int position; private int hintPosition; private int hintBCI; private HotSpotMethodDataAccessor dataAccessor; - private HotSpotMethodData methodData; - private final int codeSize; - public HotSpotProfilingInfo(HotSpotMethodData methodData, int codeSize) { + public HotSpotProfilingInfo(HotSpotMethodData methodData, HotSpotResolvedJavaMethod method) { this.methodData = methodData; - this.codeSize = codeSize; + this.method = method; hintPosition = 0; hintBCI = -1; } @Override public int getCodeSize() { - return codeSize; + return method.getCodeSize(); } @Override @@ -158,6 +162,11 @@ } @Override + public boolean isMature() { + return method.invocationCount() >= graalRuntime().getConfig().interpreterProfilingThreshold + GraalOptions.MatureProfilingInformationThreshold.getValue(); + } + + @Override public String toString() { return "HotSpotProfilingInfo<" + MetaUtil.profileToString(this, null, "; ") + ">"; } diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Fri Jun 07 17:28:01 2013 +0200 @@ -288,7 +288,7 @@ // case of a deoptimization. info = DefaultProfilingInfo.get(TriState.FALSE); } else { - info = new HotSpotProfilingInfo(methodData, codeSize); + info = new HotSpotProfilingInfo(methodData, this); } return info; } diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri Jun 07 17:28:01 2013 +0200 @@ -919,7 +919,7 @@ } BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode()); - append(new IfNode(currentGraph.unique(new IsNullNode(receiver)), trueSucc, falseSucc, 0.1)); + append(new IfNode(currentGraph.unique(new IsNullNode(receiver)), trueSucc, falseSucc, 0.01)); lastInstr = falseSucc; if (OmitHotExceptionStacktrace.getValue()) { @@ -943,7 +943,7 @@ private void emitBoundsCheck(ValueNode index, ValueNode length) { BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode()); - append(new IfNode(currentGraph.unique(new IntegerBelowThanNode(index, length)), trueSucc, falseSucc, 0.9)); + append(new IfNode(currentGraph.unique(new IntegerBelowThanNode(index, length)), trueSucc, falseSucc, 0.99)); lastInstr = trueSucc; if (OmitHotExceptionStacktrace.getValue()) { diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InlineableElement.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InlineableElement.java Fri Jun 07 17:03:07 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +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.nodes; - -public interface InlineableElement { - - int getNodeCount(); - - Iterable getInvokes(); -} diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Fri Jun 07 17:28:01 2013 +0200 @@ -35,7 +35,7 @@ * A graph that contains at least one distinguished node : the {@link #start() start} node. This * node is the start of the control flow of the graph. */ -public class StructuredGraph extends Graph implements InlineableElement { +public class StructuredGraph extends Graph { public static final int INVOCATION_ENTRY_BCI = -1; public static final long INVALID_GRAPH_ID = -1; diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java Fri Jun 07 17:28:01 2013 +0200 @@ -56,9 +56,12 @@ } private boolean assertProbabilities() { + double total = 0; for (double d : keyProbabilities) { + total += d; assert d >= 0.0 : "Cannot have negative probabilities in switch node: " + d; } + assert total > 0.999 && total < 1.001; return true; } @@ -73,6 +76,32 @@ return sum; } + public void setProbability(Node successor, double value) { + double changeInProbability = 0; + int nonZeroProbabilityCases = 0; + for (int i = 0; i < keySuccessors.length; i++) { + if (successors.get(keySuccessors[i]) == successor) { + changeInProbability += keyProbabilities[i] - value; + keyProbabilities[i] = value; + } else if (keyProbabilities[i] > 0) { + nonZeroProbabilityCases++; + } + } + + if (nonZeroProbabilityCases > 0) { + double changePerEntry = changeInProbability / nonZeroProbabilityCases; + if (changePerEntry != 0) { + for (int i = 0; i < keyProbabilities.length; i++) { + if (keyProbabilities[i] > 0) { + keyProbabilities[i] = keyProbabilities[i] + changePerEntry; + } + } + } + } + + assertProbabilities(); + } + public ValueNode value() { return value; } diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/GraphCache.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/GraphCache.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/GraphCache.java Fri Jun 07 17:28:01 2013 +0200 @@ -27,7 +27,7 @@ public interface GraphCache { - void put(StructuredGraph graph); + void put(StructuredGraph graph, boolean hasMatureProfilingInfo); StructuredGraph get(ResolvedJavaMethod method); diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Fri Jun 07 17:28:01 2013 +0200 @@ -40,7 +40,9 @@ import com.oracle.graal.phases.PhasePlan.PhasePosition; import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer; import com.oracle.graal.phases.common.InliningUtil.InlineInfo; +import com.oracle.graal.phases.common.InliningUtil.Inlineable; import com.oracle.graal.phases.common.InliningUtil.InlineableMacroNode; +import com.oracle.graal.phases.common.InliningUtil.InlineableGraph; import com.oracle.graal.phases.common.InliningUtil.InliningPolicy; import com.oracle.graal.phases.graph.*; @@ -154,10 +156,10 @@ MethodInvocation calleeInvocation = data.pushInvocation(info, parentAssumptions, invokeProbability, invokeRelevance); for (int i = 0; i < info.numberOfMethods(); i++) { - InlineableElement elem = getInlineableElement(info.methodAt(i), info.invoke(), calleeInvocation.assumptions()); + Inlineable elem = getInlineableElement(info.methodAt(i), info.invoke(), calleeInvocation.assumptions()); info.setInlinableElement(i, elem); - if (elem instanceof StructuredGraph) { - data.pushGraph((StructuredGraph) elem, invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i)); + if (elem instanceof InlineableGraph) { + data.pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i)); } else { assert elem instanceof InlineableMacroNode; data.pushDummyGraph(); @@ -215,12 +217,12 @@ } } - private InlineableElement getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, Assumptions assumptions) { + private Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, Assumptions assumptions) { Class macroNodeClass = InliningUtil.getMacroNodeClass(replacements, method); if (macroNodeClass != null) { return new InlineableMacroNode(macroNodeClass); } else { - return buildGraph(method, invoke, assumptions); + return new InlineableGraph(buildGraph(method, invoke, assumptions)); } } @@ -296,6 +298,8 @@ } private StructuredGraph parseBytecodes(StructuredGraph newGraph, Assumptions assumptions) { + boolean hasMatureProfilingInfo = newGraph.method().getProfilingInfo().isMature(); + if (plan != null) { plan.runPhases(PhasePosition.AFTER_PARSING, newGraph); } @@ -311,7 +315,7 @@ new CullFrameStatesPhase().apply(newGraph); } if (CacheGraphs.getValue() && cache != null) { - cache.put(newGraph.copy()); + cache.put(newGraph.copy(), hasMatureProfilingInfo); } return newGraph; } @@ -387,7 +391,7 @@ protected static int determineNodeCount(InlineInfo info) { int nodes = 0; for (int i = 0; i < info.numberOfMethods(); i++) { - InlineableElement elem = info.inlineableElementAt(i); + Inlineable elem = info.inlineableElementAt(i); if (elem != null) { nodes += elem.getNodeCount(); } @@ -398,10 +402,10 @@ protected static double determineInvokeProbability(InlineInfo info) { double invokeProbability = 0; for (int i = 0; i < info.numberOfMethods(); i++) { - InlineableElement callee = info.inlineableElementAt(i); + Inlineable callee = info.inlineableElementAt(i); Iterable invokes = callee.getInvokes(); if (invokes.iterator().hasNext()) { - NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure((StructuredGraph) callee).apply(); + NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(((InlineableGraph) callee).getGraph()).apply(); for (Invoke invoke : invokes) { invokeProbability += nodeProbabilities.get(invoke.asNode()); } @@ -433,15 +437,16 @@ } double inliningBonus = getInliningBonus(info); - + int nodes = determineNodeCount(info); int lowLevelGraphSize = previousLowLevelGraphSize(info); + if (SmallCompiledLowLevelGraphSize.getValue() > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue() * inliningBonus) { - return InliningUtil.logNotInlinedMethod(info, inliningDepth, "too large previous low-level graph: %d", lowLevelGraphSize); + return InliningUtil.logNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)", + lowLevelGraphSize, relevance, probability, inliningBonus, nodes); } - int nodes = determineNodeCount(info); if (nodes < TrivialInliningSize.getValue() * inliningBonus) { - return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (nodes=%d)", nodes); + return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes); } /* @@ -452,16 +457,17 @@ */ double invokes = determineInvokeProbability(info); if (LimitInlinedInvokes.getValue() > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue() * inliningBonus) { - return InliningUtil.logNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (%f)", invokes); + return InliningUtil.logNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes, + relevance, probability, inliningBonus, nodes); } double maximumNodes = computeMaximumSize(relevance, (int) (MaximumInliningSize.getValue() * inliningBonus)); if (nodes <= maximumNodes) { - return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= max=%f)", relevance, probability, + return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus, nodes, maximumNodes); } - return InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > max=%f)", relevance, probability, inliningBonus, nodes, + return InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes); } } diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Fri Jun 07 17:28:01 2013 +0200 @@ -66,7 +66,37 @@ boolean isWorthInlining(InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed); } - public static class InlineableMacroNode implements InlineableElement { + public interface Inlineable { + + int getNodeCount(); + + Iterable getInvokes(); + } + + public static class InlineableGraph implements Inlineable { + + private final StructuredGraph graph; + + public InlineableGraph(StructuredGraph graph) { + this.graph = graph; + } + + @Override + public int getNodeCount() { + return graph.getNodeCount(); + } + + @Override + public Iterable getInvokes() { + return graph.getInvokes(); + } + + public StructuredGraph getGraph() { + return graph; + } + } + + public static class InlineableMacroNode implements Inlineable { private final Class macroNodeClass; @@ -238,13 +268,13 @@ ResolvedJavaMethod methodAt(int index); - InlineableElement inlineableElementAt(int index); + Inlineable inlineableElementAt(int index); double probabilityAt(int index); double relevanceAt(int index); - void setInlinableElement(int index, InlineableElement inlineableElement); + void setInlinableElement(int index, Inlineable inlineableElement); /** * Performs the inlining described by this object and returns the node that represents the @@ -277,10 +307,10 @@ return invoke; } - protected static void inline(Invoke invoke, ResolvedJavaMethod concrete, InlineableElement inlineable, Assumptions assumptions, boolean receiverNullCheck) { + protected static void inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, Assumptions assumptions, boolean receiverNullCheck) { StructuredGraph graph = invoke.asNode().graph(); - if (inlineable instanceof StructuredGraph) { - StructuredGraph calleeGraph = (StructuredGraph) inlineable; + if (inlineable instanceof InlineableGraph) { + StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph(); InliningUtil.inline(invoke, calleeGraph, receiverNullCheck); graph.getLeafGraphIds().add(calleeGraph.graphId()); @@ -331,7 +361,7 @@ private static class ExactInlineInfo extends AbstractInlineInfo { protected final ResolvedJavaMethod concrete; - private InlineableElement inlineableElement; + private Inlineable inlineableElement; public ExactInlineInfo(Invoke invoke, ResolvedJavaMethod concrete) { super(invoke); @@ -377,13 +407,13 @@ } @Override - public InlineableElement inlineableElementAt(int index) { + public Inlineable inlineableElementAt(int index) { assert index == 0; return inlineableElement; } @Override - public void setInlinableElement(int index, InlineableElement inlineableElement) { + public void setInlinableElement(int index, Inlineable inlineableElement) { assert index == 0; this.inlineableElement = inlineableElement; } @@ -398,7 +428,7 @@ private final ResolvedJavaMethod concrete; private final ResolvedJavaType type; - private InlineableElement inlineableElement; + private Inlineable inlineableElement; public TypeGuardInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, ResolvedJavaType type) { super(invoke); @@ -418,7 +448,7 @@ } @Override - public InlineableElement inlineableElementAt(int index) { + public Inlineable inlineableElementAt(int index) { assert index == 0; return inlineableElement; } @@ -436,7 +466,7 @@ } @Override - public void setInlinableElement(int index, InlineableElement inlineableElement) { + public void setInlinableElement(int index, Inlineable inlineableElement) { assert index == 0; this.inlineableElement = inlineableElement; } @@ -491,7 +521,7 @@ private final ArrayList ptypes; private final ArrayList concretesProbabilities; private final double notRecordedTypeProbability; - private final InlineableElement[] inlineableElements; + private final Inlineable[] inlineableElements; public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList concretes, ArrayList concretesProbabilities, ArrayList ptypes, ArrayList typesToConcretes, double notRecordedTypeProbability) { @@ -504,7 +534,7 @@ this.ptypes = ptypes; this.typesToConcretes = typesToConcretes; this.notRecordedTypeProbability = notRecordedTypeProbability; - this.inlineableElements = new InlineableElement[concretes.size()]; + this.inlineableElements = new Inlineable[concretes.size()]; this.methodProbabilities = computeMethodProbabilities(); this.maximumMethodProbability = maximumMethodProbability(); assert maximumMethodProbability > 0; @@ -540,7 +570,7 @@ } @Override - public InlineableElement inlineableElementAt(int index) { + public Inlineable inlineableElementAt(int index) { assert index >= 0 && index < concretes.size(); return inlineableElements[index]; } @@ -556,7 +586,7 @@ } @Override - public void setInlinableElement(int index, InlineableElement inlineableElement) { + public void setInlinableElement(int index, Inlineable inlineableElement) { assert index >= 0 && index < concretes.size(); inlineableElements[index] = inlineableElement; } @@ -907,16 +937,12 @@ @Override public void tryToDevirtualizeInvoke(MetaAccessProvider runtime, Assumptions assumptions) { if (hasSingleMethod()) { - tryToDevirtualizeSingleMethod(graph(), runtime); + devirtualizeWithTypeSwitch(graph(), InvokeKind.Special, concretes.get(0), runtime); } else { tryToDevirtualizeMultipleMethods(graph(), runtime); } } - private void tryToDevirtualizeSingleMethod(StructuredGraph graph, MetaAccessProvider runtime) { - devirtualizeWithTypeSwitch(graph, InvokeKind.Special, concretes.get(0), runtime); - } - private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, MetaAccessProvider runtime) { MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget(); if (methodCallTarget.invokeKind() == InvokeKind.Interface) { diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Fri Jun 07 17:28:01 2013 +0200 @@ -87,11 +87,7 @@ @Option(help = "") public static final OptionValue DeoptsToDisableOptimisticOptimization = new OptionValue<>(40); @Option(help = "") - public static final OptionValue MatureExecutionsBranch = new OptionValue<>(1); - @Option(help = "") - public static final OptionValue MatureExecutionsPerSwitchCase = new OptionValue<>(1); - @Option(help = "") - public static final OptionValue MatureExecutionsTypeProfile = new OptionValue<>(1); + public static final OptionValue MatureProfilingInformationThreshold = new OptionValue<>(100); // comilation queue @Option(help = "") diff -r 4f5e5bb03184 -r 63bae87147df graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java Fri Jun 07 17:03:07 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java Fri Jun 07 17:28:01 2013 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.util.*; /** @@ -63,12 +64,104 @@ } public NodesToDoubles apply() { + adjustControlSplitProbabilities(); new PropagateProbability(graph.start()).apply(); computeLoopFactors(); new PropagateLoopFrequency(graph.start()).apply(); + assert verifyProbabilities(); return nodeProbabilities; } + /** + * Assume that paths with a DeoptimizeNode at their end are taken infrequently. + */ + private void adjustControlSplitProbabilities() { + HashSet result = new HashSet<>(); + NodeBitMap visitedNodes = new NodeBitMap(graph); + for (DeoptimizeNode n : graph.getNodes(DeoptimizeNode.class)) { + if (n.action().doesInvalidateCompilation()) { + findParentControlSplitNodes(result, n, visitedNodes); + } + } + + for (ControlSplitNode n : result) { + if (!allSuxVisited(n, visitedNodes)) { + modifyProbabilities(n, visitedNodes); + } + } + } + + private static void findParentControlSplitNodes(HashSet result, DeoptimizeNode n, NodeBitMap visitedNodes) { + ArrayDeque nodes = new ArrayDeque<>(); + nodes.push(n); + + Node currentNode; + do { + currentNode = nodes.pop(); + visitedNodes.mark(currentNode); + + for (Node pred : currentNode.cfgPredecessors()) { + FixedNode fixedPred = (FixedNode) pred; + if (allSuxVisited(fixedPred, visitedNodes) || fixedPred instanceof InvokeWithExceptionNode) { + nodes.push(fixedPred); + } else { + assert fixedPred instanceof ControlSplitNode : "only control splits can have more than one sux"; + result.add((ControlSplitNode) fixedPred); + } + } + } while (!nodes.isEmpty()); + } + + private static void modifyProbabilities(ControlSplitNode node, NodeBitMap visitedNodes) { + if (node instanceof IfNode) { + IfNode ifNode = (IfNode) node; + assert visitedNodes.isMarked(ifNode.falseSuccessor()) ^ visitedNodes.isMarked(ifNode.trueSuccessor()); + + if (visitedNodes.isMarked(ifNode.trueSuccessor())) { + if (ifNode.probability(ifNode.trueSuccessor()) > 0) { + ifNode.setTrueSuccessorProbability(0); + } + } else { + if (ifNode.probability(ifNode.trueSuccessor()) < 1) { + ifNode.setTrueSuccessorProbability(1); + } + } + } else if (node instanceof SwitchNode) { + SwitchNode switchNode = (SwitchNode) node; + for (Node sux : switchNode.successors()) { + if (visitedNodes.isMarked(sux)) { + switchNode.setProbability(sux, 0); + } + } + } else { + GraalInternalError.shouldNotReachHere(); + } + } + + private static boolean allSuxVisited(FixedNode fixedPred, NodeBitMap visitedNodes) { + for (Node sux : fixedPred.successors()) { + if (!visitedNodes.contains(sux)) { + return false; + } + } + return true; + } + + private boolean verifyProbabilities() { + if (doesNotAlwaysDeopt(graph)) { + for (DeoptimizeNode n : graph.getNodes(DeoptimizeNode.class)) { + if (n.action().doesInvalidateCompilation() && nodeProbabilities.get(n) > 0.01) { + throw new AssertionError(String.format("%s with reason %s and probability %f in graph %s", n, n.reason(), nodeProbabilities.get(n), graph)); + } + } + } + return true; + } + + private static boolean doesNotAlwaysDeopt(StructuredGraph graph) { + return graph.getNodes(ReturnNode.class).iterator().hasNext(); + } + private void computeLoopFactors() { for (LoopInfo info : loopInfos) { double frequency = info.loopFrequency(nodeProbabilities); diff -r 4f5e5bb03184 -r 63bae87147df src/share/vm/code/nmethod.cpp diff -r 4f5e5bb03184 -r 63bae87147df src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Fri Jun 07 17:03:07 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Fri Jun 07 17:28:01 2013 +0200 @@ -734,6 +734,8 @@ set_int("typeProfileWidth", TypeProfileWidth); set_int("methodProfileWidth", MethodProfileWidth); + set_int("interpreterProfilingThreshold", InvocationCounter::get_ProfileLimit()); + set_int("tlabAlignmentReserve", (int32_t)ThreadLocalAllocBuffer::alignment_reserve()); set_long("tlabIntArrayMarkWord", (intptr_t)markOopDesc::prototype()->copy_set_hash(0x2)); set_long("heapTopAddress", (jlong)(address) Universe::heap()->top_addr()); diff -r 4f5e5bb03184 -r 63bae87147df src/share/vm/interpreter/invocationCounter.hpp --- a/src/share/vm/interpreter/invocationCounter.hpp Fri Jun 07 17:03:07 2013 +0200 +++ b/src/share/vm/interpreter/invocationCounter.hpp Fri Jun 07 17:28:01 2013 +0200 @@ -95,9 +95,9 @@ Action action() const { return _action[state()]; } int count() const { return _counter >> number_of_noncount_bits; } - int get_InvocationLimit() const { return InterpreterInvocationLimit >> number_of_noncount_bits; } - int get_BackwardBranchLimit() const { return InterpreterBackwardBranchLimit >> number_of_noncount_bits; } - int get_ProfileLimit() const { return InterpreterProfileLimit >> number_of_noncount_bits; } + static int get_InvocationLimit() { return InterpreterInvocationLimit >> number_of_noncount_bits; } + static int get_BackwardBranchLimit() { return InterpreterBackwardBranchLimit >> number_of_noncount_bits; } + static int get_ProfileLimit() { return InterpreterProfileLimit >> number_of_noncount_bits; } // Test counter using scaled limits like the asm interpreter would do rather than doing // the shifts to normalize the counter.