# HG changeset patch # User Stefan Anzinger # Date 1401736085 -7200 # Node ID 31db7b7374f0f67b4d6063ef86a612ea445ff3f2 # Parent 4b24d2019286c91f81648c838715f36f5334d851# Parent 5aaef6a8985d275539e1ba39357bccf508e63ba1 Merge diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/UnsafeAccess.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/AbstractObjectStamp.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampFactory.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/StampProvider.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java Mon Jun 02 21:00:37 2014 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java Mon Jun 02 21:08:05 2014 +0200 @@ -121,10 +121,12 @@ } } - private void grow() { + public void grow() { nodeCount = Math.max(nodeCount, graph().nodeIdCount()); int newLength = Math.max((bits.length * 3 / 2) + 1, sizeForNodeCount(nodeCount)); - bits = Arrays.copyOf(bits, newLength); + if (newLength > bits.length) { + bits = Arrays.copyOf(bits, newLength); + } } private boolean check(Node node, boolean grow) { diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMConstant.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMField.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMFlag.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.hotspotvmconfig/src/com/oracle/graal/hotspotvmconfig/HotSpotVMType.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java Mon Jun 02 21:00:37 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java Mon Jun 02 21:08:05 2014 +0200 @@ -140,8 +140,10 @@ protected void run(final StructuredGraph graph, final HighTierContext context) { final InliningData data = new InliningData(graph, context, maxMethodPerInlining, canonicalizer, inliningPolicy); + assert data.repOK(); while (data.hasUnprocessedGraphs()) { boolean wasInlined = data.moveForward(); + assert data.repOK(); if (wasInlined) { inliningCount++; } diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java Mon Jun 02 21:00:37 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java Mon Jun 02 21:08:05 2014 +0200 @@ -45,56 +45,38 @@ this.graph = buildGraph(method, invoke, context, canonicalizer); } + /** + * @return a (possibly cached) graph. The caller is responsible for cloning before modification. + */ + private static StructuredGraph getOriginalGraph(final ResolvedJavaMethod method, final HighTierContext context) { + StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(context.getReplacements(), method); + if (intrinsicGraph != null) { + return intrinsicGraph; + } + StructuredGraph cachedGraph = getCachedGraph(method, context); + if (cachedGraph != null) { + return cachedGraph; + } + return null; + } + private static StructuredGraph buildGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) { - final StructuredGraph newGraph; - final boolean parseBytecodes; + StructuredGraph newGraph = getOriginalGraph(method, context); + if (newGraph == null) { + newGraph = new StructuredGraph(method); + parseBytecodes(newGraph, context, canonicalizer); + } + newGraph = newGraph.copy(); // TODO (chaeubl): copying the graph is only necessary if it is modified or if it contains // any invokes - StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(context.getReplacements(), method); - if (intrinsicGraph != null) { - newGraph = intrinsicGraph.copy(); - parseBytecodes = false; - } else { - StructuredGraph cachedGraph = getCachedGraph(method, context); - if (cachedGraph != null) { - newGraph = cachedGraph.copy(); - parseBytecodes = false; - } else { - newGraph = new StructuredGraph(method); - parseBytecodes = true; - } - } try (Debug.Scope s = Debug.scope("InlineGraph", newGraph)) { - if (parseBytecodes) { - parseBytecodes(newGraph, context, canonicalizer); - } - boolean callerHasMoreInformationAboutArguments = false; - NodeInputList args = invoke.callTarget().arguments(); - ArrayList parameterUsages = new ArrayList<>(); - for (ParameterNode param : newGraph.getNodes(ParameterNode.class).snapshot()) { - ValueNode arg = args.get(param.index()); - if (arg.isConstant()) { - Constant constant = arg.asConstant(); - newGraph.replaceFloating(param, ConstantNode.forConstant(constant, context.getMetaAccess(), newGraph)); - callerHasMoreInformationAboutArguments = true; - param.usages().snapshotTo(parameterUsages); - } else { - Stamp joinedStamp = param.stamp().join(arg.stamp()); - if (joinedStamp != null && !joinedStamp.equals(param.stamp())) { - param.setStamp(joinedStamp); - callerHasMoreInformationAboutArguments = true; - param.usages().snapshotTo(parameterUsages); - } - } - } - - if (callerHasMoreInformationAboutArguments) { - if (OptCanonicalizer.getValue()) { - canonicalizer.applyIncremental(newGraph, context, parameterUsages); - } + ArrayList parameterUsages = replaceParamsWithMoreInformativeArguments(invoke, newGraph, context); + if (parameterUsages != null && OptCanonicalizer.getValue()) { + assert !parameterUsages.isEmpty() : "The caller didn't have more information about arguments after all"; + canonicalizer.applyIncremental(newGraph, context, parameterUsages); } else { // TODO (chaeubl): if args are not more concrete, inlining should be avoided // in most cases or we could at least use the previous graph size + invoke @@ -107,6 +89,67 @@ } } + private static boolean isArgMoreInformativeThanParam(ValueNode arg, ParameterNode param) { + if (arg.isConstant()) { + return true; + } else { + Stamp joinedStamp = param.stamp().join(arg.stamp()); + if (joinedStamp != null && !joinedStamp.equals(param.stamp())) { + return true; + } + } + return false; + } + + /** + * This method detects: + *
    + *
  • + * constants among the arguments to the invoke
  • + *
  • + * arguments with more precise type than that declared by the corresponding parameter
  • + *
+ * + *

+ * The corresponding parameters are updated to reflect the above information. Before doing so, + * their usages are added to parameterUsages for later incremental + * canonicalization. + *

+ * + * @return null if no incremental canonicalization is need, a list of nodes for such + * canonicalization otherwise. + */ + private static ArrayList replaceParamsWithMoreInformativeArguments(final Invoke invoke, final StructuredGraph newGraph, final HighTierContext context) { + NodeInputList args = invoke.callTarget().arguments(); + ArrayList parameterUsages = null; + for (ParameterNode param : newGraph.getNodes(ParameterNode.class).snapshot()) { + if (param.usages().isNotEmpty()) { + ValueNode arg = args.get(param.index()); + if (arg.isConstant()) { + Constant constant = arg.asConstant(); + parameterUsages = trackParameterUsages(param, parameterUsages); + // collect param usages before replacing the param + newGraph.replaceFloating(param, ConstantNode.forConstant(constant, context.getMetaAccess(), newGraph)); + } else { + Stamp joinedStamp = param.stamp().join(arg.stamp()); + if (joinedStamp != null && !joinedStamp.equals(param.stamp())) { + param.setStamp(joinedStamp); + parameterUsages = trackParameterUsages(param, parameterUsages); + } else { + assert !isArgMoreInformativeThanParam(arg, param); + } + } + } + } + return parameterUsages; + } + + private static ArrayList trackParameterUsages(ParameterNode param, ArrayList parameterUsages) { + ArrayList result = (parameterUsages == null) ? new ArrayList<>() : parameterUsages; + param.usages().snapshotTo(result); + return result; + } + private static StructuredGraph getCachedGraph(ResolvedJavaMethod method, HighTierContext context) { if (context.getGraphCache() != null) { StructuredGraph cachedGraph = context.getGraphCache().get(method); @@ -119,24 +162,29 @@ /** * This method builds the IR nodes for newGraph and canonicalizes them. Provided - * profiling info is mature, the resulting graph is cached. + * profiling info is mature, the resulting graph is cached. The caller is responsible for + * cloning before modification.

*/ private static StructuredGraph parseBytecodes(StructuredGraph newGraph, HighTierContext context, CanonicalizerPhase canonicalizer) { - if (context.getGraphBuilderSuite() != null) { - context.getGraphBuilderSuite().apply(newGraph, context); - } - assert newGraph.start().next() != null : "graph needs to be populated the GraphBuilderSuite"; + try (Debug.Scope s = Debug.scope("InlineGraph", newGraph)) { + if (context.getGraphBuilderSuite() != null) { + context.getGraphBuilderSuite().apply(newGraph, context); + } + assert newGraph.start().next() != null : "graph needs to be populated by the GraphBuilderSuite"; - new DeadCodeEliminationPhase().apply(newGraph); + new DeadCodeEliminationPhase().apply(newGraph); - if (OptCanonicalizer.getValue()) { - canonicalizer.apply(newGraph, context); - } + if (OptCanonicalizer.getValue()) { + canonicalizer.apply(newGraph, context); + } - if (context.getGraphCache() != null) { - context.getGraphCache().put(newGraph.method(), newGraph.copy()); + if (context.getGraphCache() != null) { + context.getGraphCache().put(newGraph.method(), newGraph); + } + return newGraph; + } catch (Throwable e) { + throw Debug.handle(e); } - return newGraph; } @Override diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Mon Jun 02 21:00:37 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Mon Jun 02 21:08:05 2014 +0200 @@ -380,6 +380,7 @@ */ private boolean tryToInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInvocation, MethodInvocation parentInvocation, int inliningDepth) { InlineInfo calleeInfo = calleeInvocation.callee(); + assert iterContains(callerCallsiteHolder.graph().getInvokes(), calleeInfo.invoke()); Assumptions callerAssumptions = parentInvocation.assumptions(); metricInliningConsidered.increment(); @@ -395,6 +396,15 @@ return false; } + private static boolean iterContains(Iterable in, T elem) { + for (T i : in) { + if (i == elem) { + return true; + } + } + return false; + } + /** * Process the next invoke and enqueue all its graphs for processing. */ @@ -585,6 +595,10 @@ assert currentInvocation.callee().invoke().asNode().isAlive(); currentInvocation.incrementProcessedGraphs(); if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) { + /* + * "all of currentInvocation's graphs processed" amounts to + * "all concrete methods that come into question already had the callees they contain analyzed for inlining" + */ popInvocation(); final MethodInvocation parentInvoke = currentInvocation(); try (Debug.Scope s = Debug.scope("Inlining", inliningContext())) { @@ -596,4 +610,48 @@ return false; } + + /** + * This method checks an invariant that {@link #moveForward()} must maintain: "the top + * invocation records how many concrete target methods (for it) remain on the + * {@link #graphQueue}; those targets 'belong' to the current invocation in question." + */ + private boolean topGraphsForTopInvocation() { + if (invocationQueue.isEmpty()) { + assert graphQueue.isEmpty(); + return true; + } + if (currentInvocation().isRoot()) { + if (!graphQueue.isEmpty()) { + assert graphQueue.size() == 1; + } + return true; + } + final int remainingGraphs = currentInvocation().totalGraphs() - currentInvocation().processedGraphs(); + final Iterator iter = graphQueue.iterator(); + for (int i = (remainingGraphs - 1); i >= 0; i--) { + if (!iter.hasNext()) { + assert false; + return false; + } + CallsiteHolder queuedTargetCH = iter.next(); + Inlineable targetIE = currentInvocation().callee().inlineableElementAt(i); + if (targetIE instanceof InlineableMacroNode) { + assert queuedTargetCH == DUMMY_CALLSITE_HOLDER; + } else { + InlineableGraph targetIG = (InlineableGraph) targetIE; + assert queuedTargetCH.method().equals(targetIG.getGraph().method()); + } + } + return true; + } + + /** + * This method checks invariants for this class. Named after shorthand for + * "internal representation is ok". + */ + public boolean repOK() { + assert topGraphsForTopInvocation(); + return true; + } } diff -r 4b24d2019286 -r 31db7b7374f0 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java Mon Jun 02 21:00:37 2014 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java Mon Jun 02 21:08:05 2014 +0200 @@ -32,8 +32,7 @@ import com.oracle.graal.nodes.*; /** - * Compute probabilities for fixed nodes on the fly and cache at {@link BeginNode}s and - * {@link ControlSplitNode}s. + * Compute probabilities for fixed nodes on the fly and cache them at {@link BeginNode}s. */ public class FixedNodeProbabilityCache implements ToDoubleFunction { @@ -41,15 +40,44 @@ private final Map cache = newIdentityMap(); + /** + *

+ * Given a {@link FixedNode} this method finds the most immediate {@link BeginNode} preceding it + * that either: + *

    + *
  • has no predecessor (ie, the begin-node is a merge, in particular a loop-begin, or the + * start-node)
  • + *
  • has a control-split predecessor
  • + *
+ *

+ * + *

+ * The thus found {@link BeginNode} is equi-probable with the {@link FixedNode} it was obtained + * from. When computed for the first time (afterwards a cache lookup returns it) that + * probability is computed as follows, again depending on the begin-node's predecessor: + *

    + *
  • No predecessor. In this case the begin-node is either:
  • + *
      + *
    • a merge-node, whose probability adds up those of its forward-ends
    • + *
    • a loop-begin, with probability as above multiplied by the loop-frequency
    • + *
    + *
  • Control-split predecessor: probability of the branch times that of the control-split
  • + *
+ *

+ * + *

+ * As an exception to all the above, a probability of 1 is assumed for a {@link FixedNode} that + * appears to be dead-code (ie, lacks a predecessor). + *

+ * + */ public double applyAsDouble(FixedNode node) { assert node != null; metricComputeNodeProbability.increment(); FixedNode current = node; while (true) { - if (current == null) { - return 1D; - } + assert current != null; Node predecessor = current.predecessor(); if (current instanceof BeginNode) { if (predecessor == null) { @@ -65,6 +93,7 @@ current = (FixedNode) predecessor; } + assert current instanceof BeginNode; Double cachedValue = cache.get(current); if (cachedValue != null) { return cachedValue; diff -r 4b24d2019286 -r 31db7b7374f0 test/whitelist_baseline.txt