changeset 21075:d094ea7e0433

Move PEGraphDecoder from truffle to graal project; factor out SimplifyingGraphDecoder that performs just canonicalization but not method inlining; fix bugs
author Christian Wimmer <christian.wimmer@oracle.com>
date Tue, 21 Apr 2015 16:18:23 -0700
parents 2e35a4ea22ac
children 8f67ddf0dd3b
files graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphEncoder.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CachingPEGraphDecoder.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CachingPEGraphDecoder.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java
diffstat 12 files changed, 939 insertions(+), 845 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Apr 21 10:47:43 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Apr 21 16:18:23 2015 -0700
@@ -124,7 +124,7 @@
                 frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || replacementContext != null, graphBuilderConfig.getPlugins().getParameterPlugin());
                 parser.build(graph.start(), frameState);
 
-                connectLoopEndToBegin(graph);
+                GraphUtil.normalizeLoops(graph);
 
                 // Remove dead parameters.
                 for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
@@ -2428,27 +2428,4 @@
         assert assertionsEnabled = true;
         return assertionsEnabled;
     }
-
-    /**
-     * Remove loop header without loop ends. This can happen with degenerated loops like this one:
-     *
-     * <pre>
-     * for (;;) {
-     *     try {
-     *         break;
-     *     } catch (UnresolvedException iioe) {
-     *     }
-     * }
-     * </pre>
-     */
-    public static void connectLoopEndToBegin(StructuredGraph graph) {
-        for (LoopBeginNode begin : graph.getNodes(LoopBeginNode.TYPE)) {
-            if (begin.loopEnds().isEmpty()) {
-                assert begin.forwardEndCount() == 1;
-                graph.reduceDegenerateLoopBegin(begin);
-            } else {
-                GraphUtil.normalizeLoopBegin(begin);
-            }
-        }
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Tue Apr 21 10:47:43 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Tue Apr 21 16:18:23 2015 -0700
@@ -257,10 +257,14 @@
     }
 
     public final void decode(StructuredGraph graph, EncodedGraph encodedGraph) {
-        MethodScope methodScope = new MethodScope(graph, encodedGraph, LoopExplosionKind.NONE);
-        decode(methodScope, null);
-        cleanupGraph(methodScope, null);
-        methodScope.graph.verify();
+        try (Debug.Scope scope = Debug.scope("GraphDecoder", graph)) {
+            MethodScope methodScope = new MethodScope(graph, encodedGraph, LoopExplosionKind.NONE);
+            decode(methodScope, null);
+            cleanupGraph(methodScope, null);
+            methodScope.graph.verify();
+        } catch (Throwable ex) {
+            Debug.handle(ex);
+        }
     }
 
     protected final void decode(MethodScope methodScope, FixedWithNextNode startNode) {
@@ -287,6 +291,7 @@
                 assert loopScope.nextIterations.peekFirst().loopIteration == loopScope.loopIteration + 1;
                 loopScope = loopScope.nextIterations.removeFirst();
             } else {
+                propagateCreatedNodes(loopScope);
                 loopScope = loopScope.outer;
             }
         }
@@ -303,6 +308,19 @@
         }
     }
 
+    private static void propagateCreatedNodes(LoopScope loopScope) {
+        if (loopScope.outer == null) {
+            return;
+        }
+
+        /* Register nodes that were created while decoding the loop to the outside scope. */
+        for (int i = 0; i < loopScope.createdNodes.length; i++) {
+            if (loopScope.outer.createdNodes[i] == null) {
+                loopScope.outer.createdNodes[i] = loopScope.createdNodes[i];
+            }
+        }
+    }
+
     protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope) {
         int nodeOrderId = loopScope.nodesToProcess.nextSetBit(0);
         loopScope.nodesToProcess.clear(nodeOrderId);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphEncoder.java	Tue Apr 21 10:47:43 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphEncoder.java	Tue Apr 21 16:18:23 2015 -0700
@@ -442,9 +442,6 @@
             }
         }
 
-        for (Node expectedNode : expectedGraph.getNodes()) {
-            assert nodeMapping.get(expectedNode) != null || (expectedNode.hasNoUsages() && !(expectedNode instanceof FixedNode)) : "expectedNode";
-        }
         return true;
     }
 
@@ -486,7 +483,19 @@
         assert !actualIter.hasNext();
     }
 
-    protected static void verifyNodeEqual(Node expectedNode, Node actualNode, NodeMap<Node> nodeMapping, Deque<Pair<Node, Node>> workList, boolean ignoreEndNode) {
+    protected static void verifyNodeEqual(Node e, Node actualNode, NodeMap<Node> nodeMapping, Deque<Pair<Node, Node>> workList, boolean ignoreEndNode) {
+        Node expectedNode = e;
+        if (expectedNode instanceof PhiNode) {
+            /*
+             * The input graph can contain unnecessary (eliminatable) phi functions. Such phis are
+             * not re-created during decoding, so we need to simplify the expected node too.
+             */
+            Node singleValue = ((PhiNode) expectedNode).singleValue();
+            if (singleValue != null && singleValue != PhiNode.MULTIPLE_VALUES) {
+                expectedNode = singleValue;
+            }
+        }
+
         assert expectedNode.getClass() == actualNode.getClass();
         if (ignoreEndNode && expectedNode instanceof EndNode) {
             return;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java	Tue Apr 21 16:18:23 2015 -0700
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2015, 2015, 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;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
+
+/**
+ * Graph decoder that simplifies nodes during decoding. The standard
+ * {@link Canonicalizable#canonical node canonicalization} interface is used to canonicalize nodes
+ * during decoding. Additionally, {@link IfNode branches} and {@link IntegerSwitchNode switches}
+ * with constant conditions are simplified.
+ */
+public class SimplifyingGraphDecoder extends GraphDecoder {
+
+    protected final MetaAccessProvider metaAccess;
+    protected final ConstantReflectionProvider constantReflection;
+    protected final StampProvider stampProvider;
+    protected final boolean canonicalizeReads;
+
+    protected class PECanonicalizerTool implements CanonicalizerTool {
+        @Override
+        public MetaAccessProvider getMetaAccess() {
+            return metaAccess;
+        }
+
+        @Override
+        public ConstantReflectionProvider getConstantReflection() {
+            return constantReflection;
+        }
+
+        @Override
+        public boolean canonicalizeReads() {
+            return canonicalizeReads;
+        }
+
+        @Override
+        public boolean allUsagesAvailable() {
+            return false;
+        }
+    }
+
+    public SimplifyingGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, boolean canonicalizeReads, Architecture architecture) {
+        super(architecture);
+        this.metaAccess = metaAccess;
+        this.constantReflection = constantReflection;
+        this.stampProvider = stampProvider;
+        this.canonicalizeReads = canonicalizeReads;
+    }
+
+    @Override
+    protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) {
+        GraphUtil.normalizeLoops(methodScope.graph);
+        super.cleanupGraph(methodScope, start);
+    }
+
+    @Override
+    protected void simplifyFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) {
+        if (node instanceof IfNode) {
+            IfNode ifNode = (IfNode) node;
+            if (ifNode.condition() instanceof LogicNegationNode) {
+                ifNode.eliminateNegation();
+            }
+            if (ifNode.condition() instanceof LogicConstantNode) {
+                boolean condition = ((LogicConstantNode) ifNode.condition()).getValue();
+                AbstractBeginNode survivingSuccessor = ifNode.getSuccessor(condition);
+                AbstractBeginNode deadSuccessor = ifNode.getSuccessor(!condition);
+
+                methodScope.graph.removeSplit(ifNode, survivingSuccessor);
+                assert deadSuccessor.next() == null : "must not be parsed yet";
+                deadSuccessor.safeDelete();
+            }
+
+        } else if (node instanceof IntegerSwitchNode && ((IntegerSwitchNode) node).value().isConstant()) {
+            IntegerSwitchNode switchNode = (IntegerSwitchNode) node;
+            int value = switchNode.value().asJavaConstant().asInt();
+            AbstractBeginNode survivingSuccessor = switchNode.successorAtKey(value);
+            List<Node> allSuccessors = switchNode.successors().snapshot();
+
+            methodScope.graph.removeSplit(switchNode, survivingSuccessor);
+            for (Node successor : allSuccessors) {
+                if (successor != survivingSuccessor) {
+                    assert ((AbstractBeginNode) successor).next() == null : "must not be parsed yet";
+                    successor.safeDelete();
+                }
+            }
+
+        } else if (node instanceof Canonicalizable) {
+            Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool());
+            if (canonical == null) {
+                /*
+                 * This is a possible return value of canonicalization. However, we might need to
+                 * add additional usages later on for which we need a node. Therefore, we just do
+                 * nothing and leave the node in place.
+                 */
+            } else if (canonical != node) {
+                if (!canonical.isAlive()) {
+                    assert !canonical.isDeleted();
+                    canonical = methodScope.graph.addOrUniqueWithInputs(canonical);
+                    if (canonical instanceof FixedWithNextNode) {
+                        methodScope.graph.addBeforeFixed(node, (FixedWithNextNode) canonical);
+                    } else if (canonical instanceof ControlSinkNode) {
+                        FixedWithNextNode predecessor = (FixedWithNextNode) node.predecessor();
+                        predecessor.setNext((ControlSinkNode) canonical);
+                        node.safeDelete();
+                        for (Node successor : node.successors()) {
+                            successor.safeDelete();
+                        }
+
+                    } else {
+                        assert !(canonical instanceof FixedNode);
+                    }
+                }
+                if (!node.isDeleted()) {
+                    GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
+                    node.replaceAtUsages(canonical);
+                    node.safeDelete();
+                }
+                assert lookupNode(loopScope, nodeOrderId) == node;
+                registerNode(loopScope, nodeOrderId, canonical, true, false);
+            }
+        }
+    }
+
+    @Override
+    protected Node handleFloatingNodeBeforeAdd(MethodScope methodScope, LoopScope loopScope, Node node) {
+        if (node instanceof Canonicalizable) {
+            Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool());
+            if (canonical == null) {
+                /*
+                 * This is a possible return value of canonicalization. However, we might need to
+                 * add additional usages later on for which we need a node. Therefore, we just do
+                 * nothing and leave the node in place.
+                 */
+            } else if (canonical != node) {
+                if (!canonical.isAlive()) {
+                    assert !canonical.isDeleted();
+                    canonical = methodScope.graph.addOrUniqueWithInputs(canonical);
+                }
+                assert node.hasNoUsages();
+                // methodScope.graph.replaceFloating((FloatingNode) node, canonical);
+                return canonical;
+            }
+        }
+        return node;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Tue Apr 21 10:47:43 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Tue Apr 21 16:18:23 2015 -0700
@@ -79,7 +79,7 @@
             if (result != null) {
                 return result;
             }
-            Assumptions assumptions = graph().getAssumptions();
+            Assumptions assumptions = graph() == null ? null : graph().getAssumptions();
             if (assumptions != null) {
                 AssumptionResult<ResolvedJavaType> leafConcreteSubtype = stampType.findLeafConcreteSubtype();
                 if (leafConcreteSubtype != null) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Tue Apr 21 10:47:43 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Tue Apr 21 16:18:23 2015 -0700
@@ -225,7 +225,30 @@
         }
     }
 
-    public static void normalizeLoopBegin(LoopBeginNode begin) {
+    /**
+     * Remove loop header without loop ends. This can happen with degenerated loops like this one:
+     *
+     * <pre>
+     * for (;;) {
+     *     try {
+     *         break;
+     *     } catch (UnresolvedException iioe) {
+     *     }
+     * }
+     * </pre>
+     */
+    public static void normalizeLoops(StructuredGraph graph) {
+        for (LoopBeginNode begin : graph.getNodes(LoopBeginNode.TYPE)) {
+            if (begin.loopEnds().isEmpty()) {
+                assert begin.forwardEndCount() == 1;
+                graph.reduceDegenerateLoopBegin(begin);
+            } else {
+                normalizeLoopBegin(begin);
+            }
+        }
+    }
+
+    private static void normalizeLoopBegin(LoopBeginNode begin) {
         // Delete unnecessary loop phi functions, i.e., phi functions where all inputs are either
         // the same or the phi itself.
         for (PhiNode phi : begin.phis().snapshot()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CachingPEGraphDecoder.java	Tue Apr 21 16:18:23 2015 -0700
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, 2015, 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.replacements;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
+
+/**
+ * A graph decoder that provides all necessary encoded graphs on-the-fly (by parsing the methods and
+ * encoding the graphs).
+ */
+public class CachingPEGraphDecoder extends PEGraphDecoder {
+
+    private final Providers providers;
+    private final GraphBuilderConfiguration graphBuilderConfig;
+    private final OptimisticOptimizations optimisticOpts;
+    private final AllowAssumptions allowAssumptions;
+    private final Map<ResolvedJavaMethod, EncodedGraph> graphCache;
+
+    public CachingPEGraphDecoder(Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, AllowAssumptions allowAssumptions, Architecture architecture) {
+        super(providers.getMetaAccess(), providers.getConstantReflection(), providers.getStampProvider(), architecture);
+
+        this.providers = providers;
+        this.graphBuilderConfig = graphBuilderConfig;
+        this.optimisticOpts = optimisticOpts;
+        this.allowAssumptions = allowAssumptions;
+        this.graphCache = new HashMap<>();
+    }
+
+    private EncodedGraph createGraph(ResolvedJavaMethod method) {
+        StructuredGraph graph = new StructuredGraph(method, allowAssumptions);
+        try (Debug.Scope scope = Debug.scope("createGraph", graph)) {
+
+            new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), graphBuilderConfig, optimisticOpts, null).apply(graph);
+
+            PhaseContext context = new PhaseContext(providers);
+            new CanonicalizerPhase().apply(graph, context);
+
+            EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, architecture);
+            graphCache.put(method, encodedGraph);
+            return encodedGraph;
+
+        } catch (Throwable ex) {
+            throw Debug.handle(ex);
+        }
+    }
+
+    @Override
+    protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method) {
+        EncodedGraph result = graphCache.get(method);
+        if (result == null && method.hasBytecodes()) {
+            result = createGraph(method);
+        }
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Tue Apr 21 16:18:23 2015 -0700
@@ -0,0 +1,615 @@
+/*
+ * Copyright (c) 2015, 2015, 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.replacements;
+
+import static com.oracle.graal.compiler.common.GraalInternalError.*;
+import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.common.inlining.*;
+
+/**
+ * A graph decoder that performs partial evaluation, i.e., that performs method inlining and
+ * canonicalization/simplification of nodes during decoding.
+ *
+ * Inlining and loop explosion are configured via the plugin mechanism also used by the
+ * {@link GraphBuilderPhase}. However, not all callback methods defined in
+ * {@link GraphBuilderContext} are available since decoding is more limited than graph building.
+ *
+ * The standard {@link Canonicalizable#canonical node canonicalization} interface is used to
+ * canonicalize nodes during decoding. Additionally, {@link IfNode branches} and
+ * {@link IntegerSwitchNode switches} with constant conditions are simplified.
+ */
+public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
+
+    protected class PEMethodScope extends MethodScope {
+        /** The state of the caller method. Only non-null during method inlining. */
+        protected final PEMethodScope caller;
+        protected final LoopScope callerLoopScope;
+        protected final ResolvedJavaMethod method;
+        protected final InvokeData invokeData;
+        protected final int inliningDepth;
+
+        protected final LoopExplosionPlugin loopExplosionPlugin;
+        protected final InvocationPlugins invocationPlugins;
+        protected final InlineInvokePlugin inlineInvokePlugin;
+        protected final ParameterPlugin parameterPlugin;
+        protected final ValueNode[] arguments;
+
+        protected FrameState outerState;
+        protected FrameState exceptionState;
+        protected ExceptionPlaceholderNode exceptionPlaceholderNode;
+        protected BytecodePosition bytecodePosition;
+
+        protected PEMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData,
+                        int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, ParameterPlugin parameterPlugin,
+                        ValueNode[] arguments) {
+            super(targetGraph, encodedGraph, loopExplosionKind(method, loopExplosionPlugin));
+
+            this.caller = caller;
+            this.callerLoopScope = callerLoopScope;
+            this.method = method;
+            this.invokeData = invokeData;
+            this.inliningDepth = inliningDepth;
+            this.loopExplosionPlugin = loopExplosionPlugin;
+            this.invocationPlugins = invocationPlugins;
+            this.inlineInvokePlugin = inlineInvokePlugin;
+            this.parameterPlugin = parameterPlugin;
+            this.arguments = arguments;
+        }
+
+        public boolean isInlinedMethod() {
+            return caller != null;
+        }
+    }
+
+    protected class PENonAppendGraphBuilderContext implements GraphBuilderContext {
+        protected final PEMethodScope methodScope;
+        protected final Invoke invoke;
+
+        public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) {
+            this.methodScope = methodScope;
+            this.invoke = invoke;
+        }
+
+        @Override
+        public BailoutException bailout(String string) {
+            throw new BailoutException(string);
+        }
+
+        @Override
+        public StampProvider getStampProvider() {
+            return stampProvider;
+        }
+
+        @Override
+        public MetaAccessProvider getMetaAccess() {
+            return metaAccess;
+        }
+
+        @Override
+        public ConstantReflectionProvider getConstantReflection() {
+            return constantReflection;
+        }
+
+        @Override
+        public StructuredGraph getGraph() {
+            return methodScope.graph;
+        }
+
+        @Override
+        public int getDepth() {
+            return methodScope.inliningDepth;
+        }
+
+        @Override
+        public Replacement getReplacement() {
+            return null;
+        }
+
+        @Override
+        public <T extends ValueNode> T append(T value) {
+            throw unimplemented();
+        }
+
+        @Override
+        public <T extends ValueNode> T recursiveAppend(T value) {
+            throw unimplemented();
+        }
+
+        @Override
+        public void push(Kind kind, ValueNode value) {
+            throw unimplemented();
+        }
+
+        @Override
+        public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) {
+            throw unimplemented();
+        }
+
+        @Override
+        public void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args) {
+            throw unimplemented();
+        }
+
+        @Override
+        public FrameState createStateAfter() {
+            throw unimplemented();
+        }
+
+        @Override
+        public GraphBuilderContext getParent() {
+            throw unimplemented();
+        }
+
+        @Override
+        public ResolvedJavaMethod getMethod() {
+            throw unimplemented();
+        }
+
+        @Override
+        public int bci() {
+            return invoke.bci();
+        }
+
+        @Override
+        public InvokeKind getInvokeKind() {
+            throw unimplemented();
+        }
+
+        @Override
+        public JavaType getInvokeReturnType() {
+            throw unimplemented();
+        }
+    }
+
+    protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderContext {
+        protected FixedWithNextNode lastInstr;
+        protected ValueNode pushedNode;
+
+        public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) {
+            super(inlineScope, inlineScope.invokeData.invoke);
+            this.lastInstr = lastInstr;
+        }
+
+        @Override
+        public void push(Kind kind, ValueNode value) {
+            if (pushedNode != null) {
+                throw unimplemented("Only one push is supported");
+            }
+            pushedNode = value;
+        }
+
+        @Override
+        public FrameState createStateAfter() {
+            Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId);
+            getGraph().add(stateAfter);
+            return (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter);
+        }
+
+        @Override
+        public <T extends ValueNode> T append(T v) {
+            if (v.graph() != null) {
+                return v;
+            }
+            T added = getGraph().addOrUnique(v);
+            if (added == v) {
+                updateLastInstruction(v);
+            }
+            return added;
+        }
+
+        @Override
+        public <T extends ValueNode> T recursiveAppend(T v) {
+            if (v.graph() != null) {
+                return v;
+            }
+            T added = getGraph().addOrUniqueWithInputs(v);
+            if (added == v) {
+                updateLastInstruction(v);
+            }
+            return added;
+        }
+
+        private <T extends ValueNode> void updateLastInstruction(T v) {
+            if (v instanceof FixedNode) {
+                FixedNode fixedNode = (FixedNode) v;
+                lastInstr.setNext(fixedNode);
+                if (fixedNode instanceof FixedWithNextNode) {
+                    FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
+                    assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
+                    lastInstr = fixedWithNextNode;
+                } else {
+                    lastInstr = null;
+                }
+            }
+        }
+    }
+
+    @NodeInfo
+    static class ExceptionPlaceholderNode extends ValueNode {
+        public static final NodeClass<ExceptionPlaceholderNode> TYPE = NodeClass.create(ExceptionPlaceholderNode.class);
+
+        public ExceptionPlaceholderNode() {
+            super(TYPE, StampFactory.object());
+        }
+    }
+
+    public PEGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, Architecture architecture) {
+        super(metaAccess, constantReflection, stampProvider, true, architecture);
+    }
+
+    protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) {
+        if (loopExplosionPlugin == null) {
+            return LoopExplosionKind.NONE;
+        } else if (loopExplosionPlugin.shouldMergeExplosions(method)) {
+            return LoopExplosionKind.MERGE_EXPLODE;
+        } else if (loopExplosionPlugin.shouldExplodeLoops(method)) {
+            return LoopExplosionKind.FULL_EXPLODE;
+        } else {
+            return LoopExplosionKind.NONE;
+        }
+    }
+
+    public void decode(StructuredGraph targetGraph, ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin,
+                    ParameterPlugin parameterPlugin) {
+        PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugin,
+                        parameterPlugin, null);
+        decode(methodScope, null);
+        cleanupGraph(methodScope, null);
+        methodScope.graph.verify();
+    }
+
+    @Override
+    protected void checkLoopExplosionIteration(MethodScope s, LoopScope loopScope) {
+        PEMethodScope methodScope = (PEMethodScope) s;
+
+        if (loopScope.loopIteration > MaximumLoopExplosionCount.getValue()) {
+            String message = "too many loop explosion iterations - does the explosion not terminate for method " + methodScope.method + "?";
+            if (FailedLoopExplosionIsFatal.getValue()) {
+                throw new RuntimeException(message);
+            } else {
+                throw new BailoutException(message);
+            }
+        }
+    }
+
+    @Override
+    protected void handleInvoke(MethodScope s, LoopScope loopScope, InvokeData invokeData) {
+        PEMethodScope methodScope = (PEMethodScope) s;
+
+        /*
+         * Decode the call target, but do not add it to the graph yet. This avoids adding usages for
+         * all the arguments, which are expensive to remove again when we can inline the method.
+         */
+        assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke";
+        CallTargetNode callTarget = (CallTargetNode) decodeFloatingNode(methodScope, loopScope, invokeData.callTargetOrderId);
+        if (!(callTarget instanceof MethodCallTargetNode) || !trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget)) {
+
+            /* We know that we need an invoke, so now we can add the call target to the graph. */
+            methodScope.graph.add(callTarget);
+            registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false);
+            super.handleInvoke(methodScope, loopScope, invokeData);
+        }
+    }
+
+    protected boolean trySimplifyInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
+        // attempt to devirtualize the call
+        ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(callTarget.invokeKind(), callTarget.receiver(), callTarget.targetMethod(), invokeData.contextType);
+        if (specialCallTarget != null) {
+            callTarget.setTargetMethod(specialCallTarget);
+            callTarget.setInvokeKind(InvokeKind.Special);
+        }
+
+        if (tryInvocationPlugin(methodScope, loopScope, invokeData, callTarget)) {
+            return true;
+        }
+        if (tryInline(methodScope, loopScope, invokeData, callTarget)) {
+            return true;
+        }
+
+        if (methodScope.inlineInvokePlugin != null) {
+            methodScope.inlineInvokePlugin.notifyOfNoninlinedInvoke(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke);
+        }
+        return false;
+    }
+
+    protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
+        if (methodScope.invocationPlugins == null) {
+            return false;
+        }
+
+        Invoke invoke = invokeData.invoke;
+
+        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
+        InvocationPlugin invocationPlugin = methodScope.invocationPlugins.lookupInvocation(targetMethod);
+        if (invocationPlugin == null) {
+            return false;
+        }
+
+        ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]);
+        FixedWithNextNode invokePredecessor = (FixedWithNextNode) invoke.asNode().predecessor();
+
+        /* Remove invoke from graph so that invocation plugin can append nodes to the predecessor. */
+        invoke.asNode().replaceAtPredecessor(null);
+
+        PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, methodScope.loopExplosionPlugin,
+                        methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments);
+        PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor);
+        InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext);
+
+        if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) {
+
+            if (graphBuilderContext.lastInstr != null) {
+                registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true);
+                invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode);
+                graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData));
+            } else {
+                assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?";
+                invoke.asNode().replaceAtUsages(null);
+            }
+
+            deleteInvoke(invoke);
+            return true;
+
+        } else {
+            /* Intrinsification failed, restore original state: invoke is in Graph. */
+            invokePredecessor.setNext(invoke.asNode());
+            return false;
+        }
+    }
+
+    protected boolean tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
+        if (methodScope.inlineInvokePlugin == null || !callTarget.invokeKind().isDirect()) {
+            return false;
+        }
+
+        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
+        if (!targetMethod.canBeInlined()) {
+            return false;
+        }
+
+        ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]);
+        GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke);
+        InlineInfo inlineInfo = methodScope.inlineInvokePlugin.getInlineInfo(graphBuilderContext, targetMethod, arguments, callTarget.returnType());
+        if (inlineInfo == null) {
+            return false;
+        }
+        assert !inlineInfo.isIntrinsic && !inlineInfo.isReplacement : "not supported";
+
+        ResolvedJavaMethod inlineMethod = inlineInfo.methodToInline;
+        EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod);
+        if (graphToInline == null) {
+            return false;
+        }
+
+        Invoke invoke = invokeData.invoke;
+        FixedNode invokeNode = invoke.asNode();
+        FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor();
+        invokeNode.replaceAtPredecessor(null);
+
+        PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1,
+                        methodScope.loopExplosionPlugin, methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments);
+        /* Do the actual inlining by decoding the inlineMethod */
+        decode(inlineScope, predecessor);
+
+        ValueNode exceptionValue = null;
+        if (inlineScope.unwindNode != null) {
+            exceptionValue = inlineScope.unwindNode.exception();
+        }
+        UnwindNode unwindNode = inlineScope.unwindNode;
+
+        if (invoke instanceof InvokeWithExceptionNode) {
+            InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
+            assert invokeWithException.next() == null;
+            assert invokeWithException.exceptionEdge() == null;
+
+            if (unwindNode != null) {
+                assert unwindNode.predecessor() != null;
+                Node n = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId);
+                unwindNode.replaceAndDelete(n);
+            }
+
+        } else {
+            if (unwindNode != null && !unwindNode.isDeleted()) {
+                DeoptimizeNode deoptimizeNode = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                unwindNode.replaceAndDelete(deoptimizeNode);
+            }
+        }
+
+        assert invoke.next() == null;
+
+        ValueNode returnValue;
+        List<ReturnNode> returnNodes = inlineScope.returnNodes;
+        if (!returnNodes.isEmpty()) {
+            FixedNode n;
+            n = nodeAfterInvoke(methodScope, loopScope, invokeData);
+            if (returnNodes.size() == 1) {
+                ReturnNode returnNode = returnNodes.get(0);
+                returnValue = returnNode.result();
+                returnNode.replaceAndDelete(n);
+            } else {
+                AbstractMergeNode merge = methodScope.graph.add(new MergeNode());
+                merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId));
+                returnValue = InliningUtil.mergeReturns(merge, returnNodes, null);
+                merge.setNext(n);
+            }
+        } else {
+            returnValue = null;
+        }
+        invokeNode.replaceAtUsages(returnValue);
+
+        /*
+         * Usage the handles that we have on the return value and the exception to update the
+         * orderId->Node table.
+         */
+        registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true);
+        if (invoke instanceof InvokeWithExceptionNode) {
+            registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true);
+        }
+        if (inlineScope.exceptionPlaceholderNode != null) {
+            inlineScope.exceptionPlaceholderNode.replaceAndDelete(exceptionValue);
+        }
+        deleteInvoke(invoke);
+
+        methodScope.inlineInvokePlugin.postInline(inlineMethod);
+        return true;
+    }
+
+    public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData) {
+        FixedNode n;
+        if (invokeData.invoke instanceof InvokeWithExceptionNode) {
+            n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId);
+        } else {
+            n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId);
+        }
+        return n;
+    }
+
+    private static void deleteInvoke(Invoke invoke) {
+        /*
+         * Clean up unused nodes. We cannot just call killCFG on the invoke node because that can
+         * kill too much: nodes that are decoded later can use values that appear unused by now.
+         */
+        FrameState frameState = invoke.stateAfter();
+        invoke.asNode().safeDelete();
+        assert invoke.callTarget() == null : "must not have been added to the graph yet";
+        if (frameState != null && frameState.hasNoUsages()) {
+            frameState.safeDelete();
+        }
+    }
+
+    protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method);
+
+    @Override
+    protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node node) {
+        PEMethodScope methodScope = (PEMethodScope) s;
+
+        if (node instanceof ParameterNode) {
+            if (methodScope.arguments != null) {
+                Node result = methodScope.arguments[((ParameterNode) node).index()];
+                assert result != null;
+                return result;
+
+            } else if (methodScope.parameterPlugin != null) {
+                GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null);
+                Node result = methodScope.parameterPlugin.interceptParameter(graphBuilderContext, ((ParameterNode) node).index(), ((ParameterNode) node).stamp());
+                if (result != null) {
+                    return result;
+                }
+            }
+
+        }
+
+        return super.handleFloatingNodeBeforeAdd(methodScope, loopScope, node);
+    }
+
+    protected void ensureOuterStateDecoded(PEMethodScope methodScope) {
+        if (methodScope.outerState == null && methodScope.caller != null) {
+            FrameState stateAtReturn = methodScope.invokeData.invoke.stateAfter();
+            if (stateAtReturn == null) {
+                stateAtReturn = (FrameState) decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId);
+            }
+
+            Kind invokeReturnKind = methodScope.invokeData.invoke.asNode().getKind();
+            FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind);
+
+            /*
+             * When the encoded graph has methods inlining, we can already have a proper caller
+             * state. If not, we set the caller state here.
+             */
+            if (outerState.outerFrameState() == null && methodScope.caller != null) {
+                ensureOuterStateDecoded(methodScope.caller);
+                outerState.setOuterFrameState(methodScope.caller.outerState);
+            }
+            methodScope.outerState = outerState;
+        }
+    }
+
+    protected void ensureStateAfterDecoded(PEMethodScope methodScope) {
+        if (methodScope.invokeData.invoke.stateAfter() == null) {
+            methodScope.invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId));
+        }
+    }
+
+    protected void ensureExceptionStateDecoded(PEMethodScope methodScope) {
+        if (methodScope.exceptionState == null && methodScope.caller != null && methodScope.invokeData.invoke instanceof InvokeWithExceptionNode) {
+            ensureStateAfterDecoded(methodScope);
+
+            assert methodScope.exceptionPlaceholderNode == null;
+            methodScope.exceptionPlaceholderNode = methodScope.graph.add(new ExceptionPlaceholderNode());
+            registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false);
+            FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId);
+
+            if (exceptionState.outerFrameState() == null && methodScope.caller != null) {
+                ensureOuterStateDecoded(methodScope.caller);
+                exceptionState.setOuterFrameState(methodScope.caller.outerState);
+            }
+            methodScope.exceptionState = exceptionState;
+        }
+    }
+
+    @Override
+    protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) {
+        PEMethodScope methodScope = (PEMethodScope) s;
+
+        if (methodScope.isInlinedMethod()) {
+            if (node instanceof SimpleInfopointNode) {
+                methodScope.bytecodePosition = InliningUtil.processSimpleInfopoint(methodScope.invokeData.invoke, (SimpleInfopointNode) node, methodScope.bytecodePosition);
+                return node;
+
+            } else if (node instanceof FrameState) {
+                FrameState frameState = (FrameState) node;
+
+                ensureOuterStateDecoded(methodScope);
+                if (frameState.bci < 0) {
+                    ensureExceptionStateDecoded(methodScope);
+                }
+                return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, methodScope.method, methodScope.exceptionState, methodScope.outerState, true);
+
+            } else if (node instanceof MonitorIdNode) {
+                ensureOuterStateDecoded(methodScope);
+                InliningUtil.processMonitorId(methodScope.outerState, (MonitorIdNode) node);
+                return node;
+            }
+        }
+
+        return node;
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CachingPEGraphDecoder.java	Tue Apr 21 10:47:43 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
-import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.phases.util.*;
-
-/**
- * A graph decoder that provides all necessary encoded graphs on-the-fly (by parsing the methods and
- * encoding the graphs).
- */
-public class CachingPEGraphDecoder extends PEGraphDecoder {
-
-    private final Providers providers;
-    private final GraphBuilderConfiguration graphBuilderConfig;
-    private final AllowAssumptions allowAssumptions;
-    private final Map<ResolvedJavaMethod, EncodedGraph> graphCache;
-
-    public CachingPEGraphDecoder(Providers providers, GraphBuilderConfiguration graphBuilderConfig, AllowAssumptions allowAssumptions, Architecture architecture) {
-        super(providers.getMetaAccess(), providers.getConstantReflection(), providers.getStampProvider(), architecture);
-
-        this.providers = providers;
-        this.graphBuilderConfig = graphBuilderConfig;
-        this.allowAssumptions = allowAssumptions;
-        this.graphCache = new HashMap<>();
-    }
-
-    private EncodedGraph createGraph(ResolvedJavaMethod method) {
-        StructuredGraph graph = new StructuredGraph(method, allowAssumptions);
-        try (Debug.Scope scope = Debug.scope("createGraph", graph)) {
-
-            new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), graphBuilderConfig, TruffleCompilerImpl.Optimizations, null).apply(graph);
-
-            PhaseContext context = new PhaseContext(providers);
-            new CanonicalizerPhase().apply(graph, context);
-
-            EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, architecture);
-            graphCache.put(method, encodedGraph);
-            return encodedGraph;
-
-        } catch (Throwable ex) {
-            throw Debug.handle(ex);
-        }
-    }
-
-    @Override
-    protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method) {
-        EncodedGraph result = graphCache.get(method);
-        if (result == null && method.hasBytecodes()) {
-            result = createGraph(method);
-        }
-        return result;
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java	Tue Apr 21 10:47:43 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,725 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, 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 static com.oracle.graal.compiler.common.GraalInternalError.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
-import com.oracle.graal.java.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.common.inlining.*;
-
-/**
- * A graph decoder that performs partial evaluation, i.e., that performs method inlining and
- * canonicalization/simplification of nodes during decoding.
- *
- * Inlining and loop explosion are configured via the plugin mechanism also used by the
- * {@link GraphBuilderPhase}. However, not all callback methods defined in
- * {@link GraphBuilderContext} are available since decoding is more limited than graph building.
- *
- * The standard {@link Canonicalizable#canonical node canonicalization} interface is used to
- * canonicalize nodes during decoding. Additionally, {@link IfNode branches} and
- * {@link IntegerSwitchNode switches} with constant conditions are simplified.
- */
-public abstract class PEGraphDecoder extends GraphDecoder {
-
-    protected final MetaAccessProvider metaAccess;
-    protected final ConstantReflectionProvider constantReflection;
-    protected final StampProvider stampProvider;
-
-    protected class PEMethodScope extends MethodScope {
-        /** The state of the caller method. Only non-null during method inlining. */
-        protected final PEMethodScope caller;
-        protected final LoopScope callerLoopScope;
-        protected final ResolvedJavaMethod method;
-        protected final InvokeData invokeData;
-        protected final int inliningDepth;
-
-        protected final LoopExplosionPlugin loopExplosionPlugin;
-        protected final InvocationPlugins invocationPlugins;
-        protected final InlineInvokePlugin inlineInvokePlugin;
-        protected final ParameterPlugin parameterPlugin;
-        protected final ValueNode[] arguments;
-
-        protected FrameState outerState;
-        protected FrameState exceptionState;
-        protected ExceptionPlaceholderNode exceptionPlaceholderNode;
-        protected BytecodePosition bytecodePosition;
-
-        protected PEMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData,
-                        int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin, ParameterPlugin parameterPlugin,
-                        ValueNode[] arguments) {
-            super(targetGraph, encodedGraph, loopExplosionKind(method, loopExplosionPlugin));
-
-            this.caller = caller;
-            this.callerLoopScope = callerLoopScope;
-            this.method = method;
-            this.invokeData = invokeData;
-            this.inliningDepth = inliningDepth;
-            this.loopExplosionPlugin = loopExplosionPlugin;
-            this.invocationPlugins = invocationPlugins;
-            this.inlineInvokePlugin = inlineInvokePlugin;
-            this.parameterPlugin = parameterPlugin;
-            this.arguments = arguments;
-        }
-
-        public boolean isInlinedMethod() {
-            return caller != null;
-        }
-    }
-
-    protected class PECanonicalizerTool implements CanonicalizerTool {
-        @Override
-        public MetaAccessProvider getMetaAccess() {
-            return metaAccess;
-        }
-
-        @Override
-        public ConstantReflectionProvider getConstantReflection() {
-            return constantReflection;
-        }
-
-        @Override
-        public boolean canonicalizeReads() {
-            return true;
-        }
-
-        @Override
-        public boolean allUsagesAvailable() {
-            return false;
-        }
-    }
-
-    protected class PENonAppendGraphBuilderContext implements GraphBuilderContext {
-        protected final PEMethodScope methodScope;
-        protected final Invoke invoke;
-
-        public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) {
-            this.methodScope = methodScope;
-            this.invoke = invoke;
-        }
-
-        @Override
-        public BailoutException bailout(String string) {
-            throw new BailoutException(string);
-        }
-
-        @Override
-        public StampProvider getStampProvider() {
-            return stampProvider;
-        }
-
-        @Override
-        public MetaAccessProvider getMetaAccess() {
-            return metaAccess;
-        }
-
-        @Override
-        public ConstantReflectionProvider getConstantReflection() {
-            return constantReflection;
-        }
-
-        @Override
-        public StructuredGraph getGraph() {
-            return methodScope.graph;
-        }
-
-        @Override
-        public int getDepth() {
-            return methodScope.inliningDepth;
-        }
-
-        @Override
-        public Replacement getReplacement() {
-            return null;
-        }
-
-        @Override
-        public <T extends ValueNode> T append(T value) {
-            throw unimplemented();
-        }
-
-        @Override
-        public <T extends ValueNode> T recursiveAppend(T value) {
-            throw unimplemented();
-        }
-
-        @Override
-        public void push(Kind kind, ValueNode value) {
-            throw unimplemented();
-        }
-
-        @Override
-        public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) {
-            throw unimplemented();
-        }
-
-        @Override
-        public void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args) {
-            throw unimplemented();
-        }
-
-        @Override
-        public FrameState createStateAfter() {
-            throw unimplemented();
-        }
-
-        @Override
-        public GraphBuilderContext getParent() {
-            throw unimplemented();
-        }
-
-        @Override
-        public ResolvedJavaMethod getMethod() {
-            throw unimplemented();
-        }
-
-        @Override
-        public int bci() {
-            return invoke.bci();
-        }
-
-        @Override
-        public InvokeKind getInvokeKind() {
-            throw unimplemented();
-        }
-
-        @Override
-        public JavaType getInvokeReturnType() {
-            throw unimplemented();
-        }
-    }
-
-    protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderContext {
-        protected FixedWithNextNode lastInstr;
-        protected ValueNode pushedNode;
-
-        public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) {
-            super(inlineScope, inlineScope.invokeData.invoke);
-            this.lastInstr = lastInstr;
-        }
-
-        @Override
-        public void push(Kind kind, ValueNode value) {
-            if (pushedNode != null) {
-                throw unimplemented("Only one push is supported");
-            }
-            pushedNode = value;
-        }
-
-        @Override
-        public FrameState createStateAfter() {
-            Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId);
-            getGraph().add(stateAfter);
-            return (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter);
-        }
-
-        @Override
-        public <T extends ValueNode> T append(T v) {
-            if (v.graph() != null) {
-                return v;
-            }
-            T added = getGraph().addOrUnique(v);
-            if (added == v) {
-                updateLastInstruction(v);
-            }
-            return added;
-        }
-
-        @Override
-        public <T extends ValueNode> T recursiveAppend(T v) {
-            if (v.graph() != null) {
-                return v;
-            }
-            T added = getGraph().addOrUniqueWithInputs(v);
-            if (added == v) {
-                updateLastInstruction(v);
-            }
-            return added;
-        }
-
-        private <T extends ValueNode> void updateLastInstruction(T v) {
-            if (v instanceof FixedNode) {
-                FixedNode fixedNode = (FixedNode) v;
-                lastInstr.setNext(fixedNode);
-                if (fixedNode instanceof FixedWithNextNode) {
-                    FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
-                    assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
-                    lastInstr = fixedWithNextNode;
-                } else {
-                    lastInstr = null;
-                }
-            }
-        }
-    }
-
-    @NodeInfo
-    static class ExceptionPlaceholderNode extends ValueNode {
-        public static final NodeClass<ExceptionPlaceholderNode> TYPE = NodeClass.create(ExceptionPlaceholderNode.class);
-
-        public ExceptionPlaceholderNode() {
-            super(TYPE, StampFactory.object());
-        }
-    }
-
-    public PEGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, Architecture architecture) {
-        super(architecture);
-        this.metaAccess = metaAccess;
-        this.constantReflection = constantReflection;
-        this.stampProvider = stampProvider;
-    }
-
-    protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) {
-        if (loopExplosionPlugin == null) {
-            return LoopExplosionKind.NONE;
-        } else if (loopExplosionPlugin.shouldMergeExplosions(method)) {
-            return LoopExplosionKind.MERGE_EXPLODE;
-        } else if (loopExplosionPlugin.shouldExplodeLoops(method)) {
-            return LoopExplosionKind.FULL_EXPLODE;
-        } else {
-            return LoopExplosionKind.NONE;
-        }
-    }
-
-    public void decode(StructuredGraph targetGraph, ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin inlineInvokePlugin,
-                    ParameterPlugin parameterPlugin) {
-        PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugin,
-                        parameterPlugin, null);
-        decode(methodScope, null);
-        cleanupGraph(methodScope, null);
-        methodScope.graph.verify();
-    }
-
-    @Override
-    protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) {
-        GraphBuilderPhase.connectLoopEndToBegin(methodScope.graph);
-        super.cleanupGraph(methodScope, start);
-    }
-
-    @Override
-    protected void checkLoopExplosionIteration(MethodScope s, LoopScope loopScope) {
-        PEMethodScope methodScope = (PEMethodScope) s;
-
-        if (loopScope.loopIteration > MaximumLoopExplosionCount.getValue()) {
-            String message = "too many loop explosion iterations - does the explosion not terminate for method " + methodScope.method + "?";
-            if (FailedLoopExplosionIsFatal.getValue()) {
-                throw new RuntimeException(message);
-            } else {
-                throw new BailoutException(message);
-            }
-        }
-    }
-
-    @Override
-    protected void handleInvoke(MethodScope s, LoopScope loopScope, InvokeData invokeData) {
-        PEMethodScope methodScope = (PEMethodScope) s;
-
-        /*
-         * Decode the call target, but do not add it to the graph yet. This avoids adding usages for
-         * all the arguments, which are expensive to remove again when we can inline the method.
-         */
-        assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke";
-        CallTargetNode callTarget = (CallTargetNode) decodeFloatingNode(methodScope, loopScope, invokeData.callTargetOrderId);
-        if (!(callTarget instanceof MethodCallTargetNode) || !trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget)) {
-
-            /* We know that we need an invoke, so now we can add the call target to the graph. */
-            methodScope.graph.add(callTarget);
-            registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false);
-            super.handleInvoke(methodScope, loopScope, invokeData);
-        }
-    }
-
-    protected boolean trySimplifyInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
-        // attempt to devirtualize the call
-        ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(callTarget.invokeKind(), callTarget.receiver(), callTarget.targetMethod(), invokeData.contextType);
-        if (specialCallTarget != null) {
-            callTarget.setTargetMethod(specialCallTarget);
-            callTarget.setInvokeKind(InvokeKind.Special);
-        }
-
-        if (tryInvocationPlugin(methodScope, loopScope, invokeData, callTarget)) {
-            return true;
-        }
-        if (tryInline(methodScope, loopScope, invokeData, callTarget)) {
-            return true;
-        }
-
-        if (methodScope.inlineInvokePlugin != null) {
-            methodScope.inlineInvokePlugin.notifyOfNoninlinedInvoke(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke);
-        }
-        return false;
-    }
-
-    protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
-        if (methodScope.invocationPlugins == null) {
-            return false;
-        }
-
-        Invoke invoke = invokeData.invoke;
-
-        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
-        InvocationPlugin invocationPlugin = methodScope.invocationPlugins.lookupInvocation(targetMethod);
-        if (invocationPlugin == null) {
-            return false;
-        }
-
-        ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]);
-        FixedWithNextNode invokePredecessor = (FixedWithNextNode) invoke.asNode().predecessor();
-
-        /* Remove invoke from graph so that invocation plugin can append nodes to the predecessor. */
-        invoke.asNode().replaceAtPredecessor(null);
-
-        PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, methodScope.loopExplosionPlugin,
-                        methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments);
-        PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor);
-        InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext);
-
-        if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) {
-
-            if (graphBuilderContext.lastInstr != null) {
-                registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true);
-                invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode);
-                graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData));
-            } else {
-                assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?";
-                invoke.asNode().replaceAtUsages(null);
-            }
-
-            deleteInvoke(invoke);
-            return true;
-
-        } else {
-            /* Intrinsification failed, restore original state: invoke is in Graph. */
-            invokePredecessor.setNext(invoke.asNode());
-            return false;
-        }
-    }
-
-    protected boolean tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
-        if (methodScope.inlineInvokePlugin == null || !callTarget.invokeKind().isDirect()) {
-            return false;
-        }
-
-        ResolvedJavaMethod targetMethod = callTarget.targetMethod();
-        if (!targetMethod.canBeInlined()) {
-            return false;
-        }
-
-        ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]);
-        GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke);
-        InlineInfo inlineInfo = methodScope.inlineInvokePlugin.getInlineInfo(graphBuilderContext, targetMethod, arguments, callTarget.returnType());
-        if (inlineInfo == null) {
-            return false;
-        }
-        assert !inlineInfo.isIntrinsic && !inlineInfo.isReplacement : "not supported";
-
-        ResolvedJavaMethod inlineMethod = inlineInfo.methodToInline;
-        EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod);
-        if (graphToInline == null) {
-            return false;
-        }
-
-        Invoke invoke = invokeData.invoke;
-        FixedNode invokeNode = invoke.asNode();
-        FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor();
-        invokeNode.replaceAtPredecessor(null);
-
-        PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1,
-                        methodScope.loopExplosionPlugin, methodScope.invocationPlugins, methodScope.inlineInvokePlugin, null, arguments);
-        /* Do the actual inlining by decoding the inlineMethod */
-        decode(inlineScope, predecessor);
-
-        ValueNode exceptionValue = null;
-        if (inlineScope.unwindNode != null) {
-            exceptionValue = inlineScope.unwindNode.exception();
-        }
-        UnwindNode unwindNode = inlineScope.unwindNode;
-
-        if (invoke instanceof InvokeWithExceptionNode) {
-            InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
-            assert invokeWithException.next() == null;
-            assert invokeWithException.exceptionEdge() == null;
-
-            if (unwindNode != null) {
-                assert unwindNode.predecessor() != null;
-                Node n = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId);
-                unwindNode.replaceAndDelete(n);
-            }
-
-        } else {
-            if (unwindNode != null && !unwindNode.isDeleted()) {
-                DeoptimizeNode deoptimizeNode = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
-                unwindNode.replaceAndDelete(deoptimizeNode);
-            }
-        }
-
-        assert invoke.next() == null;
-
-        ValueNode returnValue;
-        List<ReturnNode> returnNodes = inlineScope.returnNodes;
-        if (!returnNodes.isEmpty()) {
-            FixedNode n;
-            n = nodeAfterInvoke(methodScope, loopScope, invokeData);
-            if (returnNodes.size() == 1) {
-                ReturnNode returnNode = returnNodes.get(0);
-                returnValue = returnNode.result();
-                returnNode.replaceAndDelete(n);
-            } else {
-                AbstractMergeNode merge = methodScope.graph.add(new MergeNode());
-                merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId));
-                returnValue = InliningUtil.mergeReturns(merge, returnNodes, null);
-                merge.setNext(n);
-            }
-        } else {
-            returnValue = null;
-        }
-        invokeNode.replaceAtUsages(returnValue);
-
-        /*
-         * Usage the handles that we have on the return value and the exception to update the
-         * orderId->Node table.
-         */
-        registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true);
-        if (invoke instanceof InvokeWithExceptionNode) {
-            registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true);
-        }
-        if (inlineScope.exceptionPlaceholderNode != null) {
-            inlineScope.exceptionPlaceholderNode.replaceAndDelete(exceptionValue);
-        }
-        deleteInvoke(invoke);
-
-        methodScope.inlineInvokePlugin.postInline(inlineMethod);
-        return true;
-    }
-
-    public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData) {
-        FixedNode n;
-        if (invokeData.invoke instanceof InvokeWithExceptionNode) {
-            n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId);
-        } else {
-            n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId);
-        }
-        return n;
-    }
-
-    private static void deleteInvoke(Invoke invoke) {
-        /*
-         * Clean up unused nodes. We cannot just call killCFG on the invoke node because that can
-         * kill too much: nodes that are decoded later can use values that appear unused by now.
-         */
-        FrameState frameState = invoke.stateAfter();
-        invoke.asNode().safeDelete();
-        assert invoke.callTarget() == null : "must not have been added to the graph yet";
-        if (frameState != null && frameState.hasNoUsages()) {
-            frameState.safeDelete();
-        }
-    }
-
-    protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method);
-
-    @Override
-    protected void simplifyFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) {
-        PEMethodScope methodScope = (PEMethodScope) s;
-
-        if (node instanceof IfNode) {
-            IfNode ifNode = (IfNode) node;
-            if (ifNode.condition() instanceof LogicNegationNode) {
-                ifNode.eliminateNegation();
-            }
-            if (ifNode.condition() instanceof LogicConstantNode) {
-                boolean condition = ((LogicConstantNode) ifNode.condition()).getValue();
-                AbstractBeginNode survivingSuccessor = ifNode.getSuccessor(condition);
-                AbstractBeginNode deadSuccessor = ifNode.getSuccessor(!condition);
-
-                methodScope.graph.removeSplit(ifNode, survivingSuccessor);
-                assert deadSuccessor.next() == null : "must not be parsed yet";
-                deadSuccessor.safeDelete();
-            }
-
-        } else if (node instanceof IntegerSwitchNode && ((IntegerSwitchNode) node).value().isConstant()) {
-            IntegerSwitchNode switchNode = (IntegerSwitchNode) node;
-            int value = switchNode.value().asJavaConstant().asInt();
-            AbstractBeginNode survivingSuccessor = switchNode.successorAtKey(value);
-            List<Node> allSuccessors = switchNode.successors().snapshot();
-
-            methodScope.graph.removeSplit(switchNode, survivingSuccessor);
-            for (Node successor : allSuccessors) {
-                if (successor != survivingSuccessor) {
-                    assert ((AbstractBeginNode) successor).next() == null : "must not be parsed yet";
-                    successor.safeDelete();
-                }
-            }
-
-        } else if (node instanceof Canonicalizable) {
-            Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool());
-            if (canonical == null) {
-                /*
-                 * This is a possible return value of canonicalization. However, we might need to
-                 * add additional usages later on for which we need a node. Therefore, we just do
-                 * nothing and leave the node in place.
-                 */
-            } else if (canonical != node) {
-                if (!canonical.isAlive()) {
-                    assert !canonical.isDeleted();
-                    canonical = methodScope.graph.addOrUniqueWithInputs(canonical);
-                    if (canonical instanceof FixedWithNextNode) {
-                        methodScope.graph.addBeforeFixed(node, (FixedWithNextNode) canonical);
-                    }
-                }
-                GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
-                node.replaceAtUsages(canonical);
-                node.safeDelete();
-                assert lookupNode(loopScope, nodeOrderId) == node;
-                registerNode(loopScope, nodeOrderId, canonical, true, false);
-            }
-        }
-    }
-
-    @Override
-    protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node node) {
-        PEMethodScope methodScope = (PEMethodScope) s;
-
-        if (node instanceof ParameterNode) {
-            if (methodScope.arguments != null) {
-                Node result = methodScope.arguments[((ParameterNode) node).index()];
-                assert result != null;
-                return result;
-
-            } else if (methodScope.parameterPlugin != null) {
-                GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null);
-                Node result = methodScope.parameterPlugin.interceptParameter(graphBuilderContext, ((ParameterNode) node).index(), ((ParameterNode) node).stamp());
-                if (result != null) {
-                    return result;
-                }
-            }
-
-        } else if (node instanceof Canonicalizable) {
-            Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool());
-            if (canonical == null) {
-                /*
-                 * This is a possible return value of canonicalization. However, we might need to
-                 * add additional usages later on for which we need a node. Therefore, we just do
-                 * nothing and leave the node in place.
-                 */
-            } else if (canonical != node) {
-                if (!canonical.isAlive()) {
-                    assert !canonical.isDeleted();
-                    canonical = methodScope.graph.addOrUniqueWithInputs(canonical);
-                }
-                assert node.hasNoUsages();
-                // methodScope.graph.replaceFloating((FloatingNode) node, canonical);
-                return canonical;
-            }
-        }
-        return node;
-    }
-
-    protected void ensureOuterStateDecoded(PEMethodScope methodScope) {
-        if (methodScope.outerState == null && methodScope.caller != null) {
-            FrameState stateAtReturn = methodScope.invokeData.invoke.stateAfter();
-            if (stateAtReturn == null) {
-                stateAtReturn = (FrameState) decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId);
-            }
-
-            Kind invokeReturnKind = methodScope.invokeData.invoke.asNode().getKind();
-            FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind);
-
-            /*
-             * When the encoded graph has methods inlining, we can already have a proper caller
-             * state. If not, we set the caller state here.
-             */
-            if (outerState.outerFrameState() == null && methodScope.caller != null) {
-                ensureOuterStateDecoded(methodScope.caller);
-                outerState.setOuterFrameState(methodScope.caller.outerState);
-            }
-            methodScope.outerState = outerState;
-        }
-    }
-
-    protected void ensureStateAfterDecoded(PEMethodScope methodScope) {
-        if (methodScope.invokeData.invoke.stateAfter() == null) {
-            methodScope.invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId));
-        }
-    }
-
-    protected void ensureExceptionStateDecoded(PEMethodScope methodScope) {
-        if (methodScope.exceptionState == null && methodScope.caller != null && methodScope.invokeData.invoke instanceof InvokeWithExceptionNode) {
-            ensureStateAfterDecoded(methodScope);
-
-            assert methodScope.exceptionPlaceholderNode == null;
-            methodScope.exceptionPlaceholderNode = methodScope.graph.add(new ExceptionPlaceholderNode());
-            registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false);
-            FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId);
-
-            if (exceptionState.outerFrameState() == null && methodScope.caller != null) {
-                ensureOuterStateDecoded(methodScope.caller);
-                exceptionState.setOuterFrameState(methodScope.caller.outerState);
-            }
-            methodScope.exceptionState = exceptionState;
-        }
-    }
-
-    @Override
-    protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) {
-        PEMethodScope methodScope = (PEMethodScope) s;
-
-        if (methodScope.isInlinedMethod()) {
-            if (node instanceof SimpleInfopointNode) {
-                methodScope.bytecodePosition = InliningUtil.processSimpleInfopoint(methodScope.invokeData.invoke, (SimpleInfopointNode) node, methodScope.bytecodePosition);
-                return node;
-
-            } else if (node instanceof FrameState) {
-                FrameState frameState = (FrameState) node;
-
-                ensureOuterStateDecoded(methodScope);
-                if (frameState.bci < 0) {
-                    ensureExceptionStateDecoded(methodScope);
-                }
-                return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, methodScope.method, methodScope.exceptionState, methodScope.outerState, true);
-
-            } else if (node instanceof MonitorIdNode) {
-                ensureOuterStateDecoded(methodScope);
-                InliningUtil.processMonitorId(methodScope.outerState, (MonitorIdNode) node);
-                return node;
-            }
-        }
-
-        return node;
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Apr 21 10:47:43 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Apr 21 16:18:23 2015 -0700
@@ -340,7 +340,7 @@
         plugins.setInlineInvokePlugin(new ParsingInlineInvokePlugin((ReplacementsImpl) providers.getReplacements(), parsingInvocationPlugins, loopExplosionPlugin,
                         !PrintTruffleExpansionHistogram.getValue()));
 
-        CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(providers, newConfig, AllowAssumptions.from(graph.getAssumptions() != null), architecture);
+        CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(providers, newConfig, TruffleCompilerImpl.Optimizations, AllowAssumptions.from(graph.getAssumptions() != null), architecture);
 
         ParameterPlugin parameterPlugin = new InterceptReceiverPlugin(callTarget);
 
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Tue Apr 21 10:47:43 2015 -0700
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Tue Apr 21 16:18:23 2015 -0700
@@ -63,7 +63,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (getUsageCount() == 0) {
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
             /* If the cast is unused, it can be eliminated. */
             return input;
         }