# HG changeset patch # User Christos Kotselidis # Date 1374523457 -7200 # Node ID cea4beb67bfde815b8bef29f0e31bbb86be73cd4 # Parent e7679ec4f27ff658bf67eec60cef7d4cccb464a2# Parent 4da2141fc40f3b33a52b92660f58dde40ef99cdb Merge diff -r e7679ec4f27f -r cea4beb67bfd graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java Mon Jul 22 22:03:53 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java Mon Jul 22 22:04:17 2013 +0200 @@ -39,6 +39,8 @@ */ public class ConditionalEliminationTest extends GraalCompilerTest { + public static Object field; + static class Entry { final String name; @@ -108,7 +110,7 @@ } } else { if (b == null) { - return 3; + return -3; } else { return 4; } @@ -196,4 +198,34 @@ assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind()); } + public static void testTypeMergingSnippet(Object o, boolean b) { + if (b) { + if (!(o instanceof Double)) { + return; + } + } else { + if (!(o instanceof Integer)) { + return; + } + } + + /* + * For this test the conditional elimination has to correctly merge the type information it + * has about o, so that it can remove the check on Number. + */ + if (!(o instanceof Number)) { + field = o; + } + } + + @Test + public void testTypeMerging() { + StructuredGraph graph = parse("testTypeMergingSnippet"); + new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph); + new ConditionalEliminationPhase(runtime()).apply(graph); + new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph); + + assertEquals(0, graph.getNodes().filter(StoreFieldNode.class).count()); + } + } diff -r e7679ec4f27f -r cea4beb67bfd graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Mon Jul 22 22:03:53 2013 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Mon Jul 22 22:04:17 2013 +0200 @@ -195,7 +195,7 @@ return null; } - PhiNode phi = graph.unique(new PhiNode(currentValue.kind(), block)); + PhiNode phi = graph.add(new PhiNode(currentValue.kind(), block)); for (int i = 0; i < block.phiPredecessorCount(); i++) { phi.addInput(currentValue); } @@ -290,7 +290,7 @@ } assert !block.isPhiAtMerge(value) : "phi function for this block already created"; - PhiNode phi = graph.unique(new PhiNode(value.kind(), block)); + PhiNode phi = graph.add(new PhiNode(value.kind(), block)); phi.addInput(value); return phi; } diff -r e7679ec4f27f -r cea4beb67bfd graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Mon Jul 22 22:03:53 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Mon Jul 22 22:04:17 2013 +0200 @@ -22,8 +22,11 @@ */ package com.oracle.graal.nodes.java; +import java.lang.reflect.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -57,11 +60,15 @@ @Override public ValueNode canonical(CanonicalizerTool tool) { MetaAccessProvider runtime = tool.runtime(); - if (tool.canonicalizeReads()) { + if (tool.canonicalizeReads() && runtime != null) { ConstantNode constant = asConstant(runtime); if (constant != null) { return constant; } + PhiNode phi = asPhi(runtime); + if (phi != null) { + return phi; + } } return this; } @@ -70,16 +77,34 @@ * Gets a constant value for this load if possible. */ public ConstantNode asConstant(MetaAccessProvider runtime) { - if (runtime != null) { - Constant constant = null; - if (isStatic()) { - constant = field().readConstantValue(null); - } else if (object().isConstant() && !object().isNullConstant()) { - constant = field().readConstantValue(object().asConstant()); + Constant constant = null; + if (isStatic()) { + constant = field().readConstantValue(null); + } else if (object().isConstant() && !object().isNullConstant()) { + constant = field().readConstantValue(object().asConstant()); + } + if (constant != null) { + return ConstantNode.forConstant(constant, runtime, graph()); + } + return null; + } + + private PhiNode asPhi(MetaAccessProvider runtime) { + if (!isStatic() && Modifier.isFinal(field.getModifiers()) && object() instanceof PhiNode && ((PhiNode) object()).values().filter(NodePredicates.isNotA(ConstantNode.class)).isEmpty()) { + PhiNode phi = (PhiNode) object(); + Constant[] constants = new Constant[phi.valueCount()]; + for (int i = 0; i < phi.valueCount(); i++) { + Constant constantValue = field().readConstantValue(phi.valueAt(i).asConstant()); + if (constantValue == null) { + return null; + } + constants[i] = constantValue; } - if (constant != null) { - return ConstantNode.forConstant(constant, runtime, graph()); + PhiNode newPhi = graph().add(new PhiNode(stamp(), phi.merge())); + for (int i = 0; i < phi.valueCount(); i++) { + newPhi.addInput(ConstantNode.forConstant(constants[i], runtime, graph())); } + return newPhi; } return null; } diff -r e7679ec4f27f -r cea4beb67bfd graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Mon Jul 22 22:03:53 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Mon Jul 22 22:04:17 2013 +0200 @@ -114,7 +114,7 @@ break; } } - if (type == null && type != node.objectStamp().type()) { + if (type != null && type != node.objectStamp().type()) { newKnownTypes.put(node, type); } } diff -r e7679ec4f27f -r cea4beb67bfd 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 Mon Jul 22 22:03:53 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Mon Jul 22 22:04:17 2013 +0200 @@ -609,7 +609,7 @@ PhiNode returnValuePhi = null; if (invoke.asNode().kind() != Kind.Void) { - returnValuePhi = graph.unique(new PhiNode(invoke.asNode().kind(), returnMerge)); + returnValuePhi = graph.add(new PhiNode(invoke.asNode().kind(), returnMerge)); } MergeNode exceptionMerge = null; @@ -622,7 +622,7 @@ FixedNode exceptionSux = exceptionEdge.next(); graph.addBeforeFixed(exceptionSux, exceptionMerge); - exceptionObjectPhi = graph.unique(new PhiNode(Kind.Object, exceptionMerge)); + exceptionObjectPhi = graph.add(new PhiNode(Kind.Object, exceptionMerge)); exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Object, exceptionObjectPhi)); } diff -r e7679ec4f27f -r cea4beb67bfd 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 Mon Jul 22 22:03:53 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Mon Jul 22 22:04:17 2013 +0200 @@ -50,7 +50,7 @@ this.originalInvokeCounter = compilationThreshold; this.rootNode.setCallTarget(this); - if (TruffleProfiling.getValue()) { + if (TruffleCallTargetProfiling.getValue()) { registerCallTarget(this); } } @@ -75,7 +75,7 @@ @Override public Object call(PackedFrame caller, Arguments args) { - if (TruffleProfiling.getValue()) { + if (TruffleCallTargetProfiling.getValue()) { callCount++; } if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, compiledMethod != null)) { @@ -138,7 +138,7 @@ (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, codeSize); } - if (TruffleProfiling.getValue()) { + if (TruffleCallTargetProfiling.getValue()) { resetProfiling(); } } @@ -237,16 +237,16 @@ return inlined; } - private void printCallSiteInfo(InliningPolicy policy, List inlinableCallSites, String msg) { + private static void printCallSiteInfo(InliningPolicy policy, List inlinableCallSites, String msg) { for (InlinableCallSiteInfo candidate : inlinableCallSites) { printCallSiteInfo(policy, candidate, msg); } } - private void printCallSiteInfo(InliningPolicy policy, InlinableCallSiteInfo callSite, String msg) { + private static void printCallSiteInfo(InliningPolicy policy, InlinableCallSiteInfo callSite, String msg) { String calls = String.format("%4s/%4s", callSite.getCallCount(), policy.callerInvocationCount); String nodes = String.format("%3s/%3s", callSite.getInlineNodeCount(), policy.callerNodeCount); - OUT.printf("[truffle] %-9s %-50s |Nodes %6s |Calls %6s %7.3f |into %s\n", msg, callSite.getCallSite(), nodes, calls, policy.metric(callSite), target.getRootNode()); + OUT.printf("[truffle] %-9s %-50s |Nodes %6s |Calls %6s %7.3f |%s\n", msg, callSite.getCallSite(), nodes, calls, policy.metric(callSite), callSite.getCallSite().getCallTarget()); } private static final class InliningPolicy { @@ -405,7 +405,7 @@ private static Map callTargets; static { - if (TruffleProfiling.getValue()) { + if (TruffleCallTargetProfiling.getValue()) { callTargets = new WeakHashMap<>(); Runtime.getRuntime().addShutdownHook(new Thread() { diff -r e7679ec4f27f -r cea4beb67bfd 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 Mon Jul 22 22:03:53 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Mon Jul 22 22:04:17 2013 +0200 @@ -88,6 +88,6 @@ @Option(help = "") public static final OptionValue TraceTruffleInliningDetails = new OptionValue<>(false); @Option(help = "") - public static final OptionValue TruffleProfiling = new StableOptionValue<>(false); + public static final OptionValue TruffleCallTargetProfiling = new StableOptionValue<>(false); // @formatter:on } diff -r e7679ec4f27f -r cea4beb67bfd graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Mon Jul 22 22:03:53 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Mon Jul 22 22:04:17 2013 +0200 @@ -70,7 +70,7 @@ ValueNode cachedValue = state.getReadCache(object, store.field()); ValueNode value = state.getScalarAlias(store.value()); - if (value == cachedValue) { + if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) { effects.deleteFixedNode(store); deleted = true; } diff -r e7679ec4f27f -r cea4beb67bfd graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Mon Jul 22 22:03:53 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java Mon Jul 22 22:04:17 2013 +0200 @@ -36,8 +36,8 @@ import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.schedule.*; import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.CacheEntry; +import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry; import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.ReadCacheEntry; -import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry; public class ReadEliminationClosure extends EffectsClosure { @@ -106,6 +106,8 @@ } state.killReadCache(write.location().getLocationIdentity()); state.addCacheEntry(identifier, value); + } else { + state.killReadCache(write.location().getLocationIdentity()); } } else if (node instanceof MemoryCheckpoint.Single) { processIdentity(state, ((MemoryCheckpoint.Single) node).getLocationIdentity()); diff -r e7679ec4f27f -r cea4beb67bfd graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Mon Jul 22 22:03:53 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Mon Jul 22 22:04:17 2013 +0200 @@ -33,11 +33,6 @@ */ public abstract class Node implements Cloneable { - /** - * Utility constant representing an empty node array. - */ - public static final Node[] EMPTY_ARRAY = new Node[0]; - private Node parent; private SourceSection sourceSection; @@ -193,6 +188,22 @@ } /** + * Checks if this node is properly adopted by a parent and can be replaced. + * + * @return {@code true} if it is safe to replace this node. + */ + public final boolean isReplaceable() { + if (getParent() != null) { + for (Node sibling : getParent().getChildren()) { + if (sibling == this) { + return true; + } + } + } + return false; + } + + /** * Intended to be implemented by subclasses of {@link Node} to receive a notification when the * node is rewritten. This method is invoked before the actual replace has happened. * diff -r e7679ec4f27f -r cea4beb67bfd graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon Jul 22 22:03:53 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon Jul 22 22:04:17 2013 +0200 @@ -344,7 +344,11 @@ for (long fieldOffset : nodeClass.childrenOffsets) { Node[] children = (Node[]) unsafe.getObject(node, fieldOffset); if (children != null) { - nodes.addAll(Arrays.asList(children)); + for (Node child : children) { + if (child != null) { + nodes.add(child); + } + } } } @@ -545,23 +549,25 @@ } public static int countNodes(Node root, Class clazz) { - NodeCountVisitor nodeCount = new NodeCountVisitor(clazz); + NodeCountVisitor nodeCount = new NodeCountVisitor(root, clazz); root.accept(nodeCount); return nodeCount.nodeCount; } private static final class NodeCountVisitor implements NodeVisitor { + int nodeCount; + private final Node root; private final Class clazz; - int nodeCount; - private NodeCountVisitor(Class clazz) { + private NodeCountVisitor(Node root, Class clazz) { + this.root = root; this.clazz = clazz; } @Override public boolean visit(Node node) { - if (node instanceof RootNode && nodeCount > 0) { + if (node instanceof RootNode && node != root) { return false; } if (clazz == null || clazz.isInstance(node)) { @@ -589,7 +595,7 @@ p.print(" "); } if (parent == null) { - p.println(node.getClass().getSimpleName()); + p.println(nodeName(node)); } else { String fieldName = "unknownField"; NodeField[] fields = NodeClass.get(parent.getClass()).fields; @@ -611,7 +617,7 @@ } p.print(fieldName); p.print(" = "); - p.println(node.getClass().getSimpleName()); + p.println(nodeName(node)); } for (Node child : node.getChildren()) { @@ -649,7 +655,7 @@ return; } - p.print(node.getClass().getSimpleName()); + p.print(nodeName(node)); ArrayList childFields = new ArrayList<>(); String sep = ""; @@ -704,4 +710,7 @@ } } + private static String nodeName(Node node) { + return node.getClass().getSimpleName(); + } }