# 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