changeset 12655:2c4aa758ee18

made ConstantNodes external to a Graph (GRAAL-508)
author Doug Simon <doug.simon@oracle.com>
date Sun, 03 Nov 2013 15:27:52 +0100
parents 1c0261ebeeed
children 9334392ed279 c6cc96cc6a1f
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java
diffstat 54 files changed, 461 insertions(+), 253 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Sun Nov 03 15:27:52 2013 +0100
@@ -144,8 +144,8 @@
         StructuredGraph graph = parse("testNullnessSnippet");
         new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        for (ConstantNode constant : graph.getNodes().filter(ConstantNode.class)) {
-            if (ConstantNodeRecordsUsages || !constant.gatherUsages().isEmpty()) {
+        for (ConstantNode constant : getConstantNodes(graph)) {
+            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
                 assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
             }
         }
@@ -178,8 +178,8 @@
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
         new ConditionalEliminationPhase(getMetaAccess()).apply(graph);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
-        for (ConstantNode constant : graph.getNodes().filter(ConstantNode.class)) {
-            if (ConstantNodeRecordsUsages || !constant.gatherUsages().isEmpty()) {
+        for (ConstantNode constant : getConstantNodes(graph)) {
+            if (ConstantNodeRecordsUsages || !constant.gatherUsages(graph).isEmpty()) {
                 assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
             }
         }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Sun Nov 03 15:27:52 2013 +0100
@@ -119,9 +119,9 @@
 
     protected int countUnusedConstants(StructuredGraph graph) {
         int total = 0;
-        for (ConstantNode node : graph.getNodes().filter(ConstantNode.class)) {
+        for (ConstantNode node : getConstantNodes(graph)) {
             if (!ConstantNodeRecordsUsages) {
-                if (node.gatherUsages().isEmpty()) {
+                if (node.gatherUsages(graph).isEmpty()) {
                     total++;
                 }
             } else {
@@ -520,7 +520,6 @@
                 if (cached.isValid()) {
                     return cached;
                 }
-
             }
         }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Sun Nov 03 15:27:52 2013 +0100
@@ -29,7 +29,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -59,12 +58,9 @@
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
         new DeadCodeEliminationPhase().apply(graph);
 
-        for (Node node : graph.getNodes()) {
-            if (node instanceof ConstantNode) {
-                ConstantNode constant = (ConstantNode) node;
-                if (constant.kind() == Kind.Object && " ".equals(constant.value.asObject())) {
-                    constant.replace(ConstantNode.forObject("-", getMetaAccess(), graph));
-                }
+        for (ConstantNode node : ConstantNode.getConstantNodes(graph)) {
+            if (node.kind() == Kind.Object && " ".equals(node.getValue().asObject())) {
+                node.replace(graph, ConstantNode.forObject("-", getMetaAccess(), graph));
             }
         }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Sun Nov 03 15:27:52 2013 +0100
@@ -187,7 +187,7 @@
             }
         } else if (value instanceof ConstantNode) {
             Debug.metric("StateConstants").increment();
-            return ((ConstantNode) value).value;
+            return ((ConstantNode) value).getValue();
 
         } else if (value != null) {
             Debug.metric("StateVariables").increment();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Sun Nov 03 15:27:52 2013 +0100
@@ -159,7 +159,7 @@
         if (nodeOperands == null) {
             return null;
         }
-        Value operand = nodeOperands.get(node);
+        Value operand = !node.isExternal() ? nodeOperands.get(node) : null;
         if (operand == null) {
             return getConstantOperand(node);
         }
@@ -171,7 +171,7 @@
             Constant value = node.asConstant();
             if (value != null) {
                 if (canInlineConstant(value)) {
-                    return setResult(node, value);
+                    return !node.isExternal() ? setResult(node, value) : value;
                 } else {
                     Variable loadedValue;
                     if (constantsLoadedInCurrentBlock == null) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Sun Nov 03 15:27:52 2013 +0100
@@ -235,7 +235,7 @@
 
     public <T extends Node> T addOrUnique(T node) {
         if (node.getNodeClass().valueNumberable()) {
-            return uniqueHelper(node);
+            return uniqueHelper(node, true);
         }
         return add(node);
     }
@@ -301,27 +301,38 @@
     }
 
     /**
-     * Adds a new node to the graph, if a <i>similar</i> node already exists in the graph, the
-     * provided node will not be added to the graph but the <i>similar</i> node will be returned
-     * instead.
+     * Looks for a node <i>similar</i> to {@code node} and returns it if found. Otherwise
+     * {@code node} is added to this graph and returned.
      * 
-     * @param node
-     * @return the node which was added to the graph or a <i>similar</i> which was already in the
-     *         graph.
+     * @return a node similar to {@code node} if one exists, otherwise {@code node}
      */
     public <T extends Node & ValueNumberable> T unique(T node) {
-        assert checkValueNumberable(node);
-        return uniqueHelper(node);
+        return uniqueHelper(node, true);
+    }
+
+    /**
+     * Looks for a node <i>similar</i> to {@code node}. If not found, {@code node} is added to the
+     * cache in this graph used to canonicalize nodes.
+     * <p>
+     * Note that node must implement {@link ValueNumberable} and must be an
+     * {@linkplain Node#isExternal() external} node.
+     * 
+     * @return a node similar to {@code node} if one exists, otherwise {@code node}
+     */
+    public <T extends Node> T uniqueWithoutAdd(T node) {
+        assert node.isExternal() : node;
+        assert node instanceof ValueNumberable : node;
+        return uniqueHelper(node, false);
     }
 
     @SuppressWarnings("unchecked")
-    <T extends Node> T uniqueHelper(T node) {
+    <T extends Node> T uniqueHelper(T node, boolean addIfMissing) {
         assert node.getNodeClass().valueNumberable();
         Node other = this.findDuplicate(node);
         if (other != null) {
             return (T) other;
         } else {
-            Node result = addHelper(node);
+            Node result = addIfMissing ? addHelper(node) : node;
             if (node.getNodeClass().isLeafNode()) {
                 putNodeIntoCache(result);
             }
@@ -330,7 +341,7 @@
     }
 
     void putNodeIntoCache(Node node) {
-        assert node.graph() == this || node.graph() == null;
+        assert node.isExternal() || node.graph() == this || node.graph() == null;
         assert node.getNodeClass().valueNumberable();
         assert node.getNodeClass().isLeafNode() : node.getClass();
         cachedNodes.put(new CacheEntry(node), node);
@@ -383,13 +394,6 @@
         }
     }
 
-    private static boolean checkValueNumberable(Node node) {
-        if (!node.getNodeClass().valueNumberable()) {
-            throw new VerificationError("node is not valueNumberable").addContext(node);
-        }
-        return true;
-    }
-
     public boolean isNew(int mark, Node node) {
         return node.id >= mark;
     }
@@ -650,6 +654,7 @@
     }
 
     void register(Node node) {
+        assert !node.isExternal();
         assert node.id() == Node.INITIAL_ID;
         int id = nodes.size();
         nodes.add(id, node);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Sun Nov 03 15:27:52 2013 +0100
@@ -156,7 +156,12 @@
         return id;
     }
 
+    /**
+     * Gets the graph context of this node. This must not be called for {@linkplain #isExternal()
+     * external} nodes.
+     */
     public Graph graph() {
+        assert !isExternal() : "external node has no graph: " + this;
         return graph;
     }
 
@@ -283,6 +288,15 @@
     }
 
     /**
+     * Determines if this node has a {@linkplain #graph() graph} context or is external to any
+     * graph. The {@link #graph()} method must only be called on nodes for which this method returns
+     * true.
+     */
+    public boolean isExternal() {
+        return false;
+    }
+
+    /**
      * Finds the index of the last non-null entry in a node array. The search assumes that all
      * non-null entries precede the first null entry in the array.
      * 
@@ -517,7 +531,7 @@
         assert assertFalse(other == this, "cannot replace a node with itself");
         assert assertFalse(isDeleted(), "cannot replace deleted node");
         assert assertTrue(other == null || !other.isDeleted(), "cannot replace with deleted node %s", other);
-        assert assertTrue(other == null || other.graph() == graph, "cannot replace with node in different graph: %s", other == null ? null : other.graph());
+        assert assertTrue(other == null || other.isExternal() || other.graph() == graph, "cannot replace with node in different graph: %s", other == null || other.isExternal() ? null : other.graph());
         return true;
     }
 
@@ -574,7 +588,7 @@
         assert assertFalse(isDeleted(), "cannot clear inputs of deleted node");
 
         for (Node input : inputs()) {
-            if (input.recordsUsages()) {
+            if (input.recordsUsages() && !input.isExternal()) {
                 removeThisFromUsages(input);
                 if (input.usages().isEmpty()) {
                     NodeChangedListener listener = graph.usagesDroppedToZeroListener;
@@ -623,6 +637,7 @@
     }
 
     public final Node copyWithInputs() {
+        assert !isExternal();
         Node newNode = clone(graph);
         NodeClass clazz = getNodeClass();
         clazz.copyInputs(this, newNode);
@@ -661,6 +676,7 @@
     }
 
     final Node clone(Graph into, boolean clearInputsAndSuccessors) {
+        assert !isExternal();
         NodeClass nodeClass = getNodeClass();
         if (nodeClass.valueNumberable() && nodeClass.isLeafNode()) {
             Node otherNode = into.findNodeInCache(this);
@@ -695,6 +711,23 @@
         return newNode;
     }
 
+    /**
+     * Determines if a given node is {@linkplain Graph#uniqueWithoutAdd(Node) unique} within a given
+     * graph if the node is non-null and {@linkplain #isExternal() external}.
+     * 
+     * @param node node to check
+     * @param graph graph context to use
+     * @return true if node is null, not external or unique within {@code graph} otherwise raises a
+     *         {@link VerificationError}
+     */
+    public static boolean verifyUniqueIfExternal(Node node, Graph graph) {
+        if (node != null && node.isExternal()) {
+            Node cached = graph.findNodeInCache(node);
+            node.assertTrue(cached == node, "external node does not match canonical node %s", cached);
+        }
+        return true;
+    }
+
     protected void afterClone(@SuppressWarnings("unused") Node other) {
     }
 
@@ -703,7 +736,8 @@
         assertTrue(graph() != null, "null graph");
         for (Node input : inputs()) {
             assertTrue(!input.recordsUsages() || input.usages().contains(this), "missing usage in input %s", input);
-            assertTrue(input.graph() == graph(), "mismatching graph in input %s", input);
+            assert verifyUniqueIfExternal(input, graph());
+            assertTrue(input.isExternal() || input.graph() == graph(), "mismatching graph in input %s", input);
         }
         for (Node successor : successors()) {
             assertTrue(successor.predecessor() == this, "missing predecessor in %s (actual: %s)", successor, successor.predecessor());
@@ -757,17 +791,18 @@
     }
 
     /**
-     * hashCode and equals should always rely on object identity alone, thus hashCode and equals are
-     * final.
+     * Nodes always use an {@linkplain System#identityHashCode(Object) identity} hash code. For this
+     * reason, {@linkplain #isExternal() external} nodes should still be {@link Graph#unique unique}
+     * within the context of a graph.
      */
     @Override
     public final int hashCode() {
-        return super.hashCode();
+        return System.identityHashCode(this);
     }
 
     /**
-     * hashCode and equals should always rely on object identity alone, thus hashCode and equals are
-     * final.
+     * Equality tests must rely solely on identity. For this reason, {@linkplain #isExternal()
+     * external} nodes should still be {@link Graph#unique unique} within the context of a graph.
      */
     @Override
     public final boolean equals(Object obj) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Sun Nov 03 15:27:52 2013 +0100
@@ -30,9 +30,7 @@
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
-import com.oracle.graal.graph.Node.Input;
-import com.oracle.graal.graph.Node.Successor;
-import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.graph.Node.*;
 import com.oracle.graal.graph.spi.*;
 
 /**
@@ -835,6 +833,7 @@
             if (input != null) {
                 Node newInput = duplicationReplacement.replacement(input, true);
                 node.updateUsages(null, newInput);
+                assert Node.verifyUniqueIfExternal(newInput, node.graph());
                 putNode(node, inputOffsets[index], newInput);
             }
             index++;
@@ -887,6 +886,7 @@
             Node oldNode = list.get(i);
             if (oldNode != null) {
                 Node newNode = duplicationReplacement.replacement(oldNode, true);
+                assert Node.verifyUniqueIfExternal(newNode, node.graph());
                 result.set(i, newNode);
             }
         }
@@ -971,6 +971,7 @@
     }
 
     public boolean replaceFirstInput(Node node, Node old, Node other) {
+        assert Node.verifyUniqueIfExternal(other, node.graph());
         int index = 0;
         while (index < directInputCount) {
             Node input = getNode(node, inputOffsets[index]);
@@ -1268,6 +1269,9 @@
         InplaceUpdateClosure replacementClosure = new InplaceUpdateClosure() {
 
             public Node replacement(Node node, boolean isInput) {
+                if (node.isExternal() && node instanceof ValueNumberable) {
+                    return graph.uniqueWithoutAdd(node);
+                }
                 Node target = newNodes.get(node);
                 if (target == null) {
                     Node replacement = node;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Sun Nov 03 15:27:52 2013 +0100
@@ -160,4 +160,27 @@
             }
         };
     }
+
+    @Override
+    public String toString() {
+        Iterator<Entry<Node, T>> i = entries().iterator();
+        if (!i.hasNext()) {
+            return "{}";
+        }
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        while (true) {
+            Entry<Node, T> e = i.next();
+            Node key = e.getKey();
+            T value = e.getValue();
+            sb.append(key);
+            sb.append('=');
+            sb.append(value);
+            if (!i.hasNext()) {
+                return sb.append('}').toString();
+            }
+            sb.append(',').append(' ');
+        }
+    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java	Sun Nov 03 15:27:52 2013 +0100
@@ -60,7 +60,7 @@
 
     public void addAll(Iterable<? extends Node> nodes) {
         for (Node node : nodes) {
-            if (node.isAlive()) {
+            if (node.isAlive() && !node.isExternal()) {
                 this.add(node);
             }
         }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Sun Nov 03 15:27:52 2013 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.test;
 
 import static com.oracle.graal.api.code.CodeUtil.*;
+import static com.oracle.graal.nodes.ConstantNode.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import org.junit.*;
@@ -64,8 +65,8 @@
     @Test
     public void testStaticFinalObjectAOT() {
         StructuredGraph result = compile("getStaticFinalObject", true);
-        assertEquals(1, result.getNodes().filter(ConstantNode.class).count());
-        assertEquals(getCodeCache().getTarget().wordKind, result.getNodes().filter(ConstantNode.class).first().kind());
+        assertEquals(1, getConstantNodes(result).count());
+        assertEquals(getCodeCache().getTarget().wordKind, getConstantNodes(result).first().kind());
         assertEquals(2, result.getNodes(FloatingReadNode.class).count());
         assertEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
@@ -73,8 +74,8 @@
     @Test
     public void testStaticFinalObject() {
         StructuredGraph result = compile("getStaticFinalObject", false);
-        assertEquals(1, result.getNodes().filter(ConstantNode.class).count());
-        assertEquals(Kind.Object, result.getNodes().filter(ConstantNode.class).first().kind());
+        assertEquals(1, getConstantNodes(result).count());
+        assertEquals(Kind.Object, getConstantNodes(result).first().kind());
         assertEquals(0, result.getNodes(FloatingReadNode.class).count());
         assertEquals(0, result.getNodes().filter(ReadNode.class).count());
     }
@@ -87,7 +88,7 @@
     public void testClassObjectAOT() {
         StructuredGraph result = compile("getClassObject", true);
 
-        NodeIterable<ConstantNode> filter = result.getNodes().filter(ConstantNode.class);
+        NodeIterable<ConstantNode> filter = getConstantNodes(result);
         assertEquals(1, filter.count());
         HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(AheadOfTimeCompilationTest.class);
         assertEquals(type.klass(), filter.first().asConstant());
@@ -100,7 +101,7 @@
     public void testClassObject() {
         StructuredGraph result = compile("getClassObject", false);
 
-        NodeIterable<ConstantNode> filter = result.getNodes().filter(ConstantNode.class);
+        NodeIterable<ConstantNode> filter = getConstantNodes(result);
         assertEquals(1, filter.count());
         Object mirror = filter.first().asConstant().asObject();
         assertEquals(Class.class, mirror.getClass());
@@ -117,7 +118,7 @@
     @Test
     public void testPrimitiveClassObjectAOT() {
         StructuredGraph result = compile("getPrimitiveClassObject", true);
-        NodeIterable<ConstantNode> filter = result.getNodes().filter(ConstantNode.class);
+        NodeIterable<ConstantNode> filter = getConstantNodes(result);
         assertEquals(1, filter.count());
         assertEquals(getCodeCache().getTarget().wordKind, filter.first().kind());
 
@@ -128,7 +129,7 @@
     @Test
     public void testPrimitiveClassObject() {
         StructuredGraph result = compile("getPrimitiveClassObject", false);
-        NodeIterable<ConstantNode> filter = result.getNodes().filter(ConstantNode.class);
+        NodeIterable<ConstantNode> filter = getConstantNodes(result);
         assertEquals(1, filter.count());
         Object mirror = filter.first().asConstant().asObject();
         assertEquals(Class.class, mirror.getClass());
@@ -156,7 +157,7 @@
     private void testStringObjectCommon(boolean compileAOT) {
         StructuredGraph result = compile("getStringObject", compileAOT);
 
-        NodeIterable<ConstantNode> filter = result.getNodes().filter(ConstantNode.class);
+        NodeIterable<ConstantNode> filter = getConstantNodes(result);
         assertEquals(1, filter.count());
         Object mirror = filter.first().asConstant().asObject();
         assertEquals(String.class, mirror.getClass());
@@ -177,8 +178,8 @@
 
         assertEquals(2, result.getNodes(FloatingReadNode.class).count());
         assertEquals(1, result.getNodes(PiNode.class).count());
-        assertEquals(1, result.getNodes().filter(ConstantNode.class).count());
-        ConstantNode constant = result.getNodes().filter(ConstantNode.class).first();
+        assertEquals(1, getConstantNodes(result).count());
+        ConstantNode constant = getConstantNodes(result).first();
         assertEquals(Kind.Long, constant.kind());
         assertEquals(((HotSpotResolvedObjectType) getMetaAccess().lookupJavaType(Boolean.class)).klass(), constant.asConstant());
     }
@@ -188,8 +189,8 @@
         StructuredGraph result = compile("getBoxedBoolean", false);
         assertEquals(0, result.getNodes(FloatingReadNode.class).count());
         assertEquals(0, result.getNodes(PiNode.class).count());
-        assertEquals(1, result.getNodes().filter(ConstantNode.class).count());
-        ConstantNode constant = result.getNodes().filter(ConstantNode.class).first();
+        assertEquals(1, getConstantNodes(result).count());
+        ConstantNode constant = getConstantNodes(result).first();
         assertEquals(Kind.Object, constant.kind());
         assertEquals(Boolean.TRUE, constant.asConstant().asObject());
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java	Sun Nov 03 15:27:52 2013 +0100
@@ -695,13 +695,14 @@
         base /= scale;
         assert NumUtil.isInt(base);
 
+        StructuredGraph graph = location.graph();
         if (index == null) {
-            return ConstantNode.forInt((int) base, location.graph());
+            return ConstantNode.forInt((int) base, graph);
         } else {
             if (base == 0) {
                 return index;
             } else {
-                return IntegerArithmeticNode.add(ConstantNode.forInt((int) base, location.graph()), index);
+                return IntegerArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index);
             }
         }
     }
@@ -709,7 +710,7 @@
     private GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
         StructuredGraph g = n.graph();
         ValueNode array = n.array();
-        ValueNode arrayLength = readArrayLength(array, tool.getConstantReflection());
+        ValueNode arrayLength = readArrayLength(n.graph(), array, tool.getConstantReflection());
         if (arrayLength == null) {
             Stamp stamp = StampFactory.positiveInt();
             ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, g), stamp, BarrierType.NONE, false));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java	Sun Nov 03 15:27:52 2013 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.phases;
 
+import static com.oracle.graal.nodes.ConstantNode.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
@@ -38,8 +40,8 @@
 
     @Override
     protected boolean verify(StructuredGraph graph, PhaseContext context) {
-        for (ConstantNode node : graph.getNodes().filter(ConstantNode.class)) {
-            if (node.recordsUsages() || !node.gatherUsages().isEmpty()) {
+        for (ConstantNode node : getConstantNodes(graph)) {
+            if (node.recordsUsages() || !node.gatherUsages(graph).isEmpty()) {
                 assert !isObject(node) || isNullReference(node) || isInternedString(node) : "illegal object constant: " + node;
             }
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Sun Nov 03 15:27:52 2013 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.phases;
 
 import static com.oracle.graal.api.meta.LocationIdentity.*;
+import static com.oracle.graal.nodes.ConstantNode.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -52,23 +53,30 @@
         this.classMirrorOffset = classMirrorOffset;
     }
 
+    private FloatingReadNode getClassConstantReplacement(StructuredGraph graph, PhaseContext context, Constant constant) {
+        if (constant.getKind() == Kind.Object && constant.asObject() instanceof Class<?>) {
+            MetaAccessProvider metaAccess = context.getMetaAccess();
+            ResolvedJavaType type = metaAccess.lookupJavaType((Class<?>) constant.asObject());
+            assert type instanceof HotSpotResolvedObjectType;
+
+            Constant klass = ((HotSpotResolvedObjectType) type).klass();
+            ConstantNode klassNode = ConstantNode.forConstant(klass, metaAccess, graph);
+
+            Stamp stamp = StampFactory.exactNonNull(metaAccess.lookupJavaType(Class.class));
+            LocationNode location = graph.unique(ConstantLocationNode.create(FINAL_LOCATION, stamp.kind(), classMirrorOffset, graph));
+            FloatingReadNode freadNode = graph.unique(new FloatingReadNode(klassNode, location, null, stamp));
+            return freadNode;
+        }
+        return null;
+    }
+
     @Override
     protected void run(StructuredGraph graph, PhaseContext context) {
-        for (ConstantNode node : graph.getNodes().filter(ConstantNode.class)) {
+        for (ConstantNode node : getConstantNodes(graph)) {
             Constant constant = node.asConstant();
-            if (constant.getKind() == Kind.Object && constant.asObject() instanceof Class<?>) {
-                MetaAccessProvider metaAccess = context.getMetaAccess();
-                ResolvedJavaType type = metaAccess.lookupJavaType((Class<?>) constant.asObject());
-                assert type instanceof HotSpotResolvedObjectType;
-
-                Constant klass = ((HotSpotResolvedObjectType) type).klass();
-                ConstantNode klassNode = ConstantNode.forConstant(klass, metaAccess, graph);
-
-                Stamp stamp = StampFactory.exactNonNull(metaAccess.lookupJavaType(Class.class));
-                LocationNode location = graph.unique(ConstantLocationNode.create(FINAL_LOCATION, stamp.kind(), classMirrorOffset, graph));
-                FloatingReadNode freadNode = graph.unique(new FloatingReadNode(klassNode, location, null, stamp));
-
-                node.replace(freadNode);
+            FloatingReadNode freadNode = getClassConstantReplacement(graph, context, constant);
+            if (freadNode != null) {
+                node.replace(graph, freadNode);
             }
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Sun Nov 03 15:27:52 2013 +0100
@@ -216,7 +216,7 @@
 
                 Arguments args;
 
-                StructuredGraph graph = hub.graph();
+                StructuredGraph graph = instanceOf.graph();
                 if (hintInfo.hintHitProbability >= hintHitProbabilityThresholdForDeoptimizingSnippet()) {
                     Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph);
                     args = new Arguments(instanceofWithProfile, graph.getGuardsStage());
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Sun Nov 03 15:27:52 2013 +0100
@@ -45,6 +45,11 @@
     }
 
     @Override
+    public StructuredGraph graph() {
+        return phi.graph();
+    }
+
+    @Override
     public Direction direction() {
         Stamp stamp = rawStride.stamp();
         if (stamp instanceof IntegerStamp) {
@@ -83,7 +88,7 @@
             return rawStride;
         }
         if (op instanceof IntegerSubNode) {
-            return rawStride.graph().unique(new NegateNode(rawStride));
+            return graph().unique(new NegateNode(rawStride));
         }
         throw GraalInternalError.shouldNotReachHere();
     }
@@ -117,7 +122,7 @@
     @Override
     public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) {
         Kind fromKind = phi.kind();
-        Graph graph = phi.graph();
+        StructuredGraph graph = graph();
         ValueNode stride = strideNode();
         ValueNode maxTripCount = loop.counted().maxTripCountNode(assumePositiveTripCount);
         ValueNode initNode = this.initNode();
@@ -127,13 +132,13 @@
             maxTripCount = graph.unique(new ConvertNode(convertOp, maxTripCount));
             initNode = graph.unique(new ConvertNode(convertOp, initNode));
         }
-        return IntegerArithmeticNode.add(IntegerArithmeticNode.mul(stride, IntegerArithmeticNode.sub(maxTripCount, ConstantNode.forIntegerKind(kind, 1, graph))), initNode);
+        return IntegerArithmeticNode.add(graph, IntegerArithmeticNode.mul(graph, stride, IntegerArithmeticNode.sub(graph, maxTripCount, ConstantNode.forIntegerKind(kind, 1, graph))), initNode);
     }
 
     @Override
     public ValueNode exitValueNode() {
         ValueNode maxTripCount = loop.counted().maxTripCountNode(false);
-        return IntegerArithmeticNode.add(IntegerArithmeticNode.mul(strideNode(), maxTripCount), initNode());
+        return IntegerArithmeticNode.add(graph(), IntegerArithmeticNode.mul(graph(), strideNode(), maxTripCount), initNode());
     }
 
     @Override
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Sun Nov 03 15:27:52 2013 +0100
@@ -25,7 +25,6 @@
 import static com.oracle.graal.nodes.calc.IntegerArithmeticNode.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.loop.InductionVariable.Direction;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -54,12 +53,12 @@
     public ValueNode maxTripCountNode(boolean assumePositive) {
         StructuredGraph graph = iv.valueNode().graph();
         Kind kind = iv.valueNode().kind();
-        IntegerArithmeticNode range = IntegerArithmeticNode.sub(end, iv.initNode());
+        IntegerArithmeticNode range = IntegerArithmeticNode.sub(graph, end, iv.initNode());
         if (oneOff) {
             if (iv.direction() == Direction.Up) {
-                range = IntegerArithmeticNode.add(range, ConstantNode.forIntegerKind(kind, 1, graph));
+                range = IntegerArithmeticNode.add(graph, range, ConstantNode.forIntegerKind(kind, 1, graph));
             } else {
-                range = IntegerArithmeticNode.sub(range, ConstantNode.forIntegerKind(kind, 1, graph));
+                range = IntegerArithmeticNode.sub(graph, range, ConstantNode.forIntegerKind(kind, 1, graph));
             }
         }
         IntegerDivNode div = graph.add(new IntegerDivNode(kind, range, iv.strideNode()));
@@ -139,20 +138,20 @@
             return overflowGuard;
         }
         Kind kind = iv.valueNode().kind();
-        Graph graph = iv.valueNode().graph();
+        StructuredGraph graph = iv.valueNode().graph();
         CompareNode cond; // we use a negated guard with a < condition to achieve a >=
         ConstantNode one = ConstantNode.forIntegerKind(kind, 1, graph);
         if (iv.direction() == Direction.Up) {
-            IntegerArithmeticNode v1 = sub(ConstantNode.forIntegerKind(kind, kind.getMaxValue(), graph), sub(iv.strideNode(), one));
+            IntegerArithmeticNode v1 = sub(graph, ConstantNode.forIntegerKind(kind, kind.getMaxValue(), graph), sub(graph, iv.strideNode(), one));
             if (oneOff) {
-                v1 = sub(v1, one);
+                v1 = sub(graph, v1, one);
             }
             cond = graph.unique(new IntegerLessThanNode(v1, end));
         } else {
             assert iv.direction() == Direction.Down;
-            IntegerArithmeticNode v1 = add(ConstantNode.forIntegerKind(kind, kind.getMinValue(), graph), sub(one, iv.strideNode()));
+            IntegerArithmeticNode v1 = add(graph, ConstantNode.forIntegerKind(kind, kind.getMinValue(), graph), sub(graph, one, iv.strideNode()));
             if (oneOff) {
-                v1 = add(v1, one);
+                v1 = add(graph, v1, one);
             }
             cond = graph.unique(new IntegerLessThanNode(end, v1));
         }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Sun Nov 03 15:27:52 2013 +0100
@@ -41,6 +41,11 @@
     }
 
     @Override
+    public StructuredGraph graph() {
+        return base.graph();
+    }
+
+    @Override
     public Direction direction() {
         return base.direction();
     }
@@ -81,7 +86,7 @@
     @Override
     public ValueNode strideNode() {
         if (value instanceof IntegerSubNode && base.valueNode() == value.y()) {
-            return value.graph().unique(new NegateNode(base.strideNode()));
+            return graph().unique(new NegateNode(base.strideNode()));
         }
         return base.strideNode();
     }
@@ -123,14 +128,14 @@
 
     private ValueNode op(ValueNode b, ValueNode o) {
         if (value instanceof IntegerAddNode) {
-            return IntegerArithmeticNode.add(b, o);
+            return IntegerArithmeticNode.add(graph(), b, o);
         }
         if (value instanceof IntegerSubNode) {
             if (base.valueNode() == value.x()) {
-                return IntegerArithmeticNode.sub(b, o);
+                return IntegerArithmeticNode.sub(graph(), b, o);
             } else {
                 assert base.valueNode() == value.y();
-                return IntegerArithmeticNode.sub(o, b);
+                return IntegerArithmeticNode.sub(graph(), o, b);
             }
         }
         throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Sun Nov 03 15:27:52 2013 +0100
@@ -48,6 +48,11 @@
     }
 
     @Override
+    public StructuredGraph graph() {
+        return base.graph();
+    }
+
+    @Override
     public Direction direction() {
         Stamp stamp = scale.stamp();
         if (stamp instanceof IntegerStamp) {
@@ -68,12 +73,12 @@
 
     @Override
     public ValueNode initNode() {
-        return IntegerArithmeticNode.mul(base.initNode(), scale);
+        return IntegerArithmeticNode.mul(graph(), base.initNode(), scale);
     }
 
     @Override
     public ValueNode strideNode() {
-        return IntegerArithmeticNode.mul(base.strideNode(), scale);
+        return IntegerArithmeticNode.mul(graph(), base.strideNode(), scale);
     }
 
     @Override
@@ -98,12 +103,12 @@
 
     @Override
     public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) {
-        return IntegerArithmeticNode.mul(base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(kind, scale));
+        return IntegerArithmeticNode.mul(graph(), base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(kind, scale));
     }
 
     @Override
     public ValueNode exitValueNode() {
-        return IntegerArithmeticNode.mul(base.exitValueNode(), scale);
+        return IntegerArithmeticNode.mul(graph(), base.exitValueNode(), scale);
     }
 
     @Override
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java	Sun Nov 03 15:27:52 2013 +0100
@@ -46,6 +46,8 @@
         }
     }
 
+    public abstract StructuredGraph graph();
+
     protected final LoopEx loop;
 
     public InductionVariable(LoopEx loop) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Sun Nov 03 15:27:52 2013 +0100
@@ -77,7 +77,7 @@
     }
 
     public boolean isOutsideLoop(Node n) {
-        return !whole().contains(n);
+        return n.isExternal() || !whole().contains(n);
     }
 
     public LoopBeginNode loopBegin() {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Sun Nov 03 15:27:52 2013 +0100
@@ -72,7 +72,10 @@
     @SuppressWarnings("unchecked")
     public <New extends Node, Old extends New> New getDuplicatedNode(Old n) {
         assert isDuplicate();
-        return (New) duplicationMap.get(n);
+        if (!n.isExternal()) {
+            return (New) duplicationMap.get(n);
+        }
+        return n;
     }
 
     protected <New extends Node, Old extends New> void putDuplicatedNode(Old oldNode, New newNode) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -25,23 +25,45 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
- * The {@code ConstantNode} represents a constant such as an integer value, long, float, object
- * reference, address, etc.
+ * The {@code ConstantNode} represents a {@link Constant constant}.
  */
 @NodeInfo(shortName = "Const", nameTemplate = "Const({p#rawvalue})")
-public class ConstantNode extends FloatingNode implements LIRLowerable {
+public final class ConstantNode extends FloatingNode implements LIRLowerable {
 
-    public final Constant value;
+    private static final DebugMetric ConstantNodes = Debug.metric("ConstantNodes");
+
+    private final Constant value;
 
     protected ConstantNode(Constant value) {
         super(StampFactory.forConstant(value));
         this.value = value;
+        ConstantNodes.increment();
+    }
+
+    /**
+     * Constructs a new ConstantNode representing the specified constant.
+     * 
+     * @param value the constant
+     */
+    protected ConstantNode(Constant value, MetaAccessProvider metaAccess) {
+        super(StampFactory.forConstant(value, metaAccess));
+        this.value = value;
+        ConstantNodes.increment();
+    }
+
+    /**
+     * @return the constant value represented by this node
+     */
+    public Constant getValue() {
+        return value;
     }
 
     /**
@@ -55,24 +77,24 @@
         return ConstantNodeRecordsUsages;
     }
 
-    /**
-     * Constructs a new ConstantNode representing the specified constant.
-     * 
-     * @param value the constant
-     */
-    protected ConstantNode(Constant value, MetaAccessProvider metaAccess) {
-        super(StampFactory.forConstant(value, metaAccess));
-        this.value = value;
+    @Override
+    public boolean isAlive() {
+        return true;
+    }
+
+    @Override
+    public boolean isExternal() {
+        return true;
     }
 
     /**
      * Computes the usages of this node by iterating over all the nodes in the graph, searching for
      * those that have this node as an input.
      */
-    public List<Node> gatherUsages() {
+    public List<Node> gatherUsages(StructuredGraph graph) {
         assert !ConstantNodeRecordsUsages;
         List<Node> usages = new ArrayList<>();
-        for (Node node : graph().getNodes()) {
+        for (Node node : graph.getNodes()) {
             for (Node input : node.inputs()) {
                 if (input == this) {
                     usages.add(node);
@@ -82,20 +104,45 @@
         return usages;
     }
 
-    public void replace(Node replacement) {
+    /**
+     * Gathers all the {@link ConstantNode}s that are inputs to the {@linkplain Graph#getNodes()
+     * live nodes} in a given graph. This is an expensive operation that should only be used in
+     * test/verification/AOT code.
+     */
+    public static NodeIterable<ConstantNode> getConstantNodes(StructuredGraph graph) {
+        Map<ConstantNode, ConstantNode> result = new HashMap<>();
+        for (Node node : graph.getNodes()) {
+            for (Node input : node.inputs()) {
+                if (input instanceof ConstantNode) {
+                    result.put((ConstantNode) input, (ConstantNode) input);
+                }
+            }
+        }
+        return new ConstantNodeList(result.keySet());
+    }
+
+    /**
+     * Replaces this node at its usages with another node. If {@value #ConstantNodeRecordsUsages} is
+     * false, this is an expensive operation that should only be used in test/verification/AOT code.
+     */
+    public void replace(StructuredGraph graph, Node replacement) {
         if (!recordsUsages()) {
-            List<Node> usages = gatherUsages();
+            List<Node> usages = gatherUsages(graph);
             for (Node usage : usages) {
                 usage.replaceFirstInput(this, replacement);
             }
-            graph().removeFloating(this);
+            if (!isExternal()) {
+                graph.removeFloating(this);
+            }
         } else {
+            assert graph == graph();
             graph().replaceFloating(this, replacement);
         }
     }
 
     @Override
     public void generate(LIRGeneratorTool gen) {
+        assert ConstantNodeRecordsUsages : "LIR generator should generate constants per-usage";
         if (gen.canInlineConstant(value) || onlyUsedInVirtualState()) {
             gen.setResult(this, value);
         } else {
@@ -118,9 +165,9 @@
         if (constant.getKind().getStackKind() == Kind.Int && constant.getKind() != Kind.Int) {
             return forInt(constant.asInt(), graph);
         } else if (constant.getKind() == Kind.Object) {
-            return graph.unique(new ConstantNode(constant, metaAccess));
+            return unique(graph, new ConstantNode(constant, metaAccess));
         } else {
-            return graph.unique(new ConstantNode(constant));
+            return unique(graph, new ConstantNode(constant));
         }
     }
 
@@ -136,100 +183,95 @@
      * Returns a node for a double constant.
      * 
      * @param d the double value for which to create the instruction
-     * @param graph
      * @return a node for a double constant
      */
     public static ConstantNode forDouble(double d, Graph graph) {
-        return graph.unique(new ConstantNode(Constant.forDouble(d)));
+        return unique(graph, new ConstantNode(Constant.forDouble(d)));
     }
 
     /**
      * Returns a node for a float constant.
      * 
      * @param f the float value for which to create the instruction
-     * @param graph
      * @return a node for a float constant
      */
     public static ConstantNode forFloat(float f, Graph graph) {
-        return graph.unique(new ConstantNode(Constant.forFloat(f)));
+        return unique(graph, new ConstantNode(Constant.forFloat(f)));
     }
 
     /**
      * Returns a node for an long constant.
      * 
      * @param i the long value for which to create the instruction
-     * @param graph
      * @return a node for an long constant
      */
     public static ConstantNode forLong(long i, Graph graph) {
-        return graph.unique(new ConstantNode(Constant.forLong(i)));
+        return unique(graph, new ConstantNode(Constant.forLong(i)));
     }
 
     /**
      * Returns a node for an integer constant.
      * 
      * @param i the integer value for which to create the instruction
-     * @param graph
      * @return a node for an integer constant
      */
     public static ConstantNode forInt(int i, Graph graph) {
-        return graph.unique(new ConstantNode(Constant.forInt(i)));
+        return unique(graph, new ConstantNode(Constant.forInt(i)));
     }
 
     /**
      * Returns a node for a boolean constant.
      * 
      * @param i the boolean value for which to create the instruction
-     * @param graph
      * @return a node representing the boolean
      */
     public static ConstantNode forBoolean(boolean i, Graph graph) {
-        return graph.unique(new ConstantNode(Constant.forInt(i ? 1 : 0)));
+        return unique(graph, new ConstantNode(Constant.forInt(i ? 1 : 0)));
     }
 
     /**
      * Returns a node for a byte constant.
      * 
      * @param i the byte value for which to create the instruction
-     * @param graph
      * @return a node representing the byte
      */
     public static ConstantNode forByte(byte i, Graph graph) {
-        return graph.unique(new ConstantNode(Constant.forInt(i)));
+        return unique(graph, new ConstantNode(Constant.forInt(i)));
     }
 
     /**
      * Returns a node for a char constant.
      * 
      * @param i the char value for which to create the instruction
-     * @param graph
      * @return a node representing the char
      */
     public static ConstantNode forChar(char i, Graph graph) {
-        return graph.unique(new ConstantNode(Constant.forInt(i)));
+        return unique(graph, new ConstantNode(Constant.forInt(i)));
     }
 
     /**
      * Returns a node for a short constant.
      * 
      * @param i the short value for which to create the instruction
-     * @param graph
      * @return a node representing the short
      */
     public static ConstantNode forShort(short i, Graph graph) {
-        return graph.unique(new ConstantNode(Constant.forInt(i)));
+        return unique(graph, new ConstantNode(Constant.forInt(i)));
     }
 
     /**
      * Returns a node for an object constant.
      * 
      * @param o the object value for which to create the instruction
-     * @param graph
      * @return a node representing the object
      */
     public static ConstantNode forObject(Object o, MetaAccessProvider metaAccess, Graph graph) {
         assert !(o instanceof Constant) : "wrapping a Constant into a Constant";
-        return graph.unique(new ConstantNode(Constant.forObject(o), metaAccess));
+        return unique(graph, new ConstantNode(Constant.forObject(o), metaAccess));
+    }
+
+    private static ConstantNode unique(Graph graph, ConstantNode node) {
+        return graph.uniqueWithoutAdd(node);
     }
 
     public static ConstantNode forIntegerKind(Kind kind, long value, Graph graph) {
@@ -292,4 +334,15 @@
             return super.toString(verbosity);
         }
     }
+
+    static class ConstantNodeList extends NodeList<ConstantNode> {
+
+        public ConstantNodeList(Collection<ConstantNode> nodes) {
+            super(nodes.toArray(new ConstantNode[nodes.size()]));
+        }
+
+        @Override
+        protected void update(ConstantNode oldNode, ConstantNode newNode) {
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -110,7 +110,7 @@
      * @return {@code true} if this value represents the null constant
      */
     public final boolean isNullConstant() {
-        return this instanceof ConstantNode && ((ConstantNode) this).value.isNull();
+        return this instanceof ConstantNode && ((ConstantNode) this).getValue().isNull();
     }
 
     /**
@@ -121,7 +121,7 @@
      */
     public final Constant asConstant() {
         if (this instanceof ConstantNode) {
-            return ((ConstantNode) this).value;
+            return ((ConstantNode) this).getValue();
         }
         return null;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -83,7 +83,7 @@
         }
     }
 
-    public static BinaryNode add(ValueNode x, ValueNode y) {
+    public static BinaryNode add(StructuredGraph graph, ValueNode x, ValueNode y) {
         assert x.kind() == y.kind();
         switch (x.kind()) {
             case Byte:
@@ -91,7 +91,7 @@
             case Short:
             case Int:
             case Long:
-                return IntegerArithmeticNode.add(x, y);
+                return IntegerArithmeticNode.add(graph, x, y);
             case Float:
             case Double:
                 return x.graph().unique(new FloatAddNode(x.kind(), x, y, false));
@@ -100,7 +100,7 @@
         }
     }
 
-    public static BinaryNode sub(ValueNode x, ValueNode y) {
+    public static BinaryNode sub(StructuredGraph graph, ValueNode x, ValueNode y) {
         assert x.kind() == y.kind();
         switch (x.kind()) {
             case Byte:
@@ -108,7 +108,7 @@
             case Short:
             case Int:
             case Long:
-                return IntegerArithmeticNode.sub(x, y);
+                return IntegerArithmeticNode.sub(graph, x, y);
             case Float:
             case Double:
                 return x.graph().unique(new FloatSubNode(x.kind(), x, y, false));
@@ -117,7 +117,7 @@
         }
     }
 
-    public static BinaryNode mul(ValueNode x, ValueNode y) {
+    public static BinaryNode mul(StructuredGraph graph, ValueNode x, ValueNode y) {
         assert x.kind() == y.kind();
         switch (x.kind()) {
             case Byte:
@@ -125,7 +125,7 @@
             case Short:
             case Int:
             case Long:
-                return IntegerArithmeticNode.mul(x, y);
+                return IntegerArithmeticNode.mul(graph, x, y);
             case Float:
             case Double:
                 return x.graph().unique(new FloatMulNode(x.kind(), x, y, false));
@@ -168,9 +168,10 @@
     //@formatter:on
     /**
      * Tries to re-associate values which satisfy the criterion. For example with a constantness
-     * criterion : (a + 2) + 1 => a + (1 + 2)<br>
-     * This method accepts only reassociable operations (see
-     * {@linkplain #canTryReassociate(BinaryNode)}) such as +, -, *, &, | and ^
+     * criterion: {@code (a + 2) + 1 => a + (1 + 2)}
+     * <p>
+     * This method accepts only {@linkplain #canTryReassociate(BinaryNode) reassociable} operations
+     * such as +, -, *, &, | and ^
      */
     public static BinaryNode reassociate(BinaryNode node, NodePredicate criterion) {
         assert canTryReassociate(node);
@@ -217,28 +218,29 @@
         ValueNode a = match2.getOtherValue(other);
         if (node instanceof IntegerAddNode || node instanceof IntegerSubNode) {
             BinaryNode associated;
+            StructuredGraph graph = node.graph();
             if (invertM1) {
-                associated = IntegerArithmeticNode.sub(m2, m1);
+                associated = IntegerArithmeticNode.sub(graph, m2, m1);
             } else if (invertM2) {
-                associated = IntegerArithmeticNode.sub(m1, m2);
+                associated = IntegerArithmeticNode.sub(graph, m1, m2);
             } else {
-                associated = IntegerArithmeticNode.add(m1, m2);
+                associated = IntegerArithmeticNode.add(graph, m1, m2);
             }
             if (invertA) {
-                return IntegerArithmeticNode.sub(associated, a);
+                return IntegerArithmeticNode.sub(graph, associated, a);
             }
             if (aSub) {
-                return IntegerArithmeticNode.sub(a, associated);
+                return IntegerArithmeticNode.sub(graph, a, associated);
             }
-            return IntegerArithmeticNode.add(a, associated);
+            return IntegerArithmeticNode.add(graph, a, associated);
         } else if (node instanceof IntegerMulNode) {
-            return IntegerArithmeticNode.mul(a, IntegerAddNode.mul(m1, m2));
+            return IntegerArithmeticNode.mul(node.graph(), a, IntegerAddNode.mul(node.graph(), m1, m2));
         } else if (node instanceof AndNode) {
-            return BitLogicNode.and(a, BitLogicNode.and(m1, m2));
+            return BitLogicNode.and(node.graph(), a, BitLogicNode.and(node.graph(), m1, m2));
         } else if (node instanceof OrNode) {
-            return BitLogicNode.or(a, BitLogicNode.or(m1, m2));
+            return BitLogicNode.or(node.graph(), a, BitLogicNode.or(node.graph(), m1, m2));
         } else if (node instanceof XorNode) {
-            return BitLogicNode.xor(a, BitLogicNode.xor(m1, m2));
+            return BitLogicNode.xor(node.graph(), a, BitLogicNode.xor(node.graph(), m1, m2));
         } else {
             throw GraalInternalError.shouldNotReachHere();
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -43,9 +42,8 @@
         assert kind == Kind.Int || kind == Kind.Long;
     }
 
-    public static BitLogicNode and(ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind() && v1.graph() == v2.graph();
-        Graph graph = v1.graph();
+    public static BitLogicNode and(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        assert v1.kind() == v2.kind();
         switch (v1.kind()) {
             case Int:
                 return graph.unique(new AndNode(Kind.Int, v1, v2));
@@ -56,9 +54,8 @@
         }
     }
 
-    public static BitLogicNode or(ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind() && v1.graph() == v2.graph();
-        Graph graph = v1.graph();
+    public static BitLogicNode or(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        assert v1.kind() == v2.kind();
         switch (v1.kind()) {
             case Int:
                 return graph.unique(new OrNode(Kind.Int, v1, v2));
@@ -69,9 +66,8 @@
         }
     }
 
-    public static BitLogicNode xor(ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind() && v1.graph() == v2.graph();
-        Graph graph = v1.graph();
+    public static BitLogicNode xor(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        assert v1.kind() == v2.kind();
         switch (v1.kind()) {
             case Int:
                 return graph.unique(new XorNode(Kind.Int, v1, v2));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -144,7 +144,7 @@
         return this;
     }
 
-    public static CompareNode createCompareNode(Condition condition, ValueNode x, ValueNode y) {
+    public static CompareNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
         assert x.kind() == y.kind();
         assert condition.isCanonical() : "condition is not canonical: " + condition;
         assert x.kind() != Kind.Double && x.kind() != Kind.Float;
@@ -166,6 +166,6 @@
             comparison = new IntegerBelowThanNode(x, y);
         }
 
-        return x.graph().unique(comparison);
+        return graph.unique(comparison);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -113,8 +113,8 @@
         generator.emitConditional(this);
     }
 
-    private ConditionalNode(Condition condition, ValueNode x, ValueNode y) {
-        this(createCompareNode(condition, x, y));
+    private ConditionalNode(@InjectedNodeParameter StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
+        this(createCompareNode(graph, condition, x, y));
     }
 
     private ConditionalNode(ValueNode type, ValueNode object) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -80,17 +80,17 @@
             }
             if (c < 0) {
                 if (kind() == Kind.Int) {
-                    return IntegerArithmeticNode.sub(x(), ConstantNode.forInt((int) -c, graph()));
+                    return IntegerArithmeticNode.sub(graph(), x(), ConstantNode.forInt((int) -c, graph()));
                 } else {
                     assert kind() == Kind.Long;
-                    return IntegerArithmeticNode.sub(x(), ConstantNode.forLong(-c, graph()));
+                    return IntegerArithmeticNode.sub(graph(), x(), ConstantNode.forLong(-c, graph()));
                 }
             }
         }
         if (x() instanceof NegateNode) {
-            return IntegerArithmeticNode.sub(y(), ((NegateNode) x()).x());
+            return IntegerArithmeticNode.sub(graph(), y(), ((NegateNode) x()).x());
         } else if (y() instanceof NegateNode) {
-            return IntegerArithmeticNode.sub(x(), ((NegateNode) y()).x());
+            return IntegerArithmeticNode.sub(graph(), x(), ((NegateNode) y()).x());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -34,9 +33,8 @@
         assert kind == Kind.Int || kind == Kind.Long;
     }
 
-    public static IntegerAddNode add(ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind() && v1.graph() == v2.graph();
-        Graph graph = v1.graph();
+    public static IntegerAddNode add(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        assert v1.kind() == v2.kind();
         switch (v1.kind()) {
             case Int:
                 return graph.unique(new IntegerAddNode(Kind.Int, v1, v2));
@@ -47,9 +45,8 @@
         }
     }
 
-    public static IntegerMulNode mul(ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind() && v1.graph() == v2.graph();
-        Graph graph = v1.graph();
+    public static IntegerMulNode mul(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        assert v1.kind() == v2.kind();
         switch (v1.kind()) {
             case Int:
                 return graph.unique(new IntegerMulNode(Kind.Int, v1, v2));
@@ -60,9 +57,8 @@
         }
     }
 
-    public static IntegerSubNode sub(ValueNode v1, ValueNode v2) {
-        assert v1.kind() == v2.kind() && v1.graph() == v2.graph();
-        Graph graph = v1.graph();
+    public static IntegerSubNode sub(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        assert v1.kind() == v2.kind();
         switch (v1.kind()) {
             case Int:
                 return graph.unique(new IntegerSubNode(Kind.Int, v1, v2));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -60,7 +60,7 @@
         } else {
             if (x().isConstant() && x().asConstant().asLong() == 0) {
                 // 0 |<| y is the same as 0 != y
-                return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(Condition.EQ, x(), y())));
+                return graph().unique(new LogicNegationNode(CompareNode.createCompareNode(graph(), Condition.EQ, x(), y())));
             }
 
             if (x().stamp() instanceof IntegerStamp && y().stamp() instanceof IntegerStamp) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -79,7 +79,7 @@
                     }
                     RightShiftNode sign = graph().unique(new RightShiftNode(kind(), x(), ConstantNode.forInt(bits - 1, graph())));
                     UnsignedRightShiftNode round = graph().unique(new UnsignedRightShiftNode(kind(), sign, ConstantNode.forInt(bits - log2, graph())));
-                    dividend = IntegerArithmeticNode.add(dividend, round);
+                    dividend = IntegerArithmeticNode.add(graph(), dividend, round);
                 }
                 RightShiftNode shift = graph().unique(new RightShiftNode(kind(), dividend, ConstantNode.forInt(log2, graph())));
                 if (c < 0) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -99,10 +99,10 @@
             }
             if (c < 0) {
                 if (kind() == Kind.Int) {
-                    return IntegerArithmeticNode.add(x(), ConstantNode.forInt((int) -c, graph()));
+                    return IntegerArithmeticNode.add(graph(), x(), ConstantNode.forInt((int) -c, graph()));
                 } else {
                     assert kind() == Kind.Long;
-                    return IntegerArithmeticNode.add(x(), ConstantNode.forLong(-c, graph()));
+                    return IntegerArithmeticNode.add(graph(), x(), ConstantNode.forLong(-c, graph()));
                 }
             }
         } else if (x().isConstant()) {
@@ -113,7 +113,7 @@
             return BinaryNode.reassociate(this, ValueNode.isConstantPredicate());
         }
         if (y() instanceof NegateNode) {
-            return IntegerArithmeticNode.add(x(), ((NegateNode) y()).x());
+            return IntegerArithmeticNode.add(graph(), x(), ((NegateNode) y()).x());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -82,7 +82,7 @@
         }
         if (x() instanceof IntegerSubNode) {
             IntegerSubNode sub = (IntegerSubNode) x;
-            return IntegerArithmeticNode.sub(sub.y(), sub.x());
+            return IntegerArithmeticNode.sub(graph(), sub.y(), sub.x());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -82,7 +82,7 @@
             IndexedLocationNode yIdx = (IndexedLocationNode) y;
             if (xIdx.getIndexScaling() == yIdx.getIndexScaling()) {
                 long displacement = xIdx.getDisplacement() + yIdx.getDisplacement();
-                ValueNode index = IntegerArithmeticNode.add(xIdx.getIndex(), yIdx.getIndex());
+                ValueNode index = IntegerArithmeticNode.add(graph(), xIdx.getIndex(), yIdx.getIndex());
                 return IndexedLocationNode.create(getLocationIdentity(), getValueKind(), displacement, index, graph(), xIdx.getIndexScaling());
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -47,7 +47,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        ValueNode length = readArrayLength(array(), tool.getConstantReflection());
+        ValueNode length = readArrayLength(graph(), array(), tool.getConstantReflection());
         if (length != null) {
             return length;
         }
@@ -57,10 +57,12 @@
     /**
      * Gets the length of an array if possible.
      * 
+     * @param graph TODO
      * @param array an array
+     * 
      * @return a node representing the length of {@code array} or null if it is not available
      */
-    public static ValueNode readArrayLength(ValueNode array, ConstantReflectionProvider constantReflection) {
+    public static ValueNode readArrayLength(StructuredGraph graph, ValueNode array, ConstantReflectionProvider constantReflection) {
         if (array instanceof ArrayLengthProvider) {
             ValueNode length = ((ArrayLengthProvider) array).length();
             if (length != null) {
@@ -72,7 +74,7 @@
             if (constantValue != null && constantValue.isNonNull()) {
                 Integer constantLength = constantReflection.lookupArrayLength(constantValue);
                 if (constantLength != null) {
-                    return ConstantNode.forInt(constantLength, array.graph());
+                    return ConstantNode.forInt(constantLength, graph);
                 }
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Sun Nov 03 15:27:52 2013 +0100
@@ -160,6 +160,12 @@
                 return forFloat(kind, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble()));
             case Illegal:
                 return illegal(Kind.Illegal);
+            case Object:
+                if (value.isNull()) {
+                    return alwaysNull();
+                } else {
+                    return objectNonNull();
+                }
             default:
                 throw new GraalInternalError("unexpected kind: %s", kind);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Sun Nov 03 15:27:52 2013 +0100
@@ -123,7 +123,7 @@
     }
 
     public static void killWithUnusedFloatingInputs(Node node) {
-        if (node.recordsUsages()) {
+        if (node.recordsUsages() && !node.isExternal()) {
             List<Node> floatingInputs = node.inputs().filter(isFloatingNode()).snapshot();
             node.safeDelete();
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Sun Nov 03 15:27:52 2013 +0100
@@ -510,7 +510,7 @@
                     PiNode piNode;
                     if (isNull) {
                         ConstantNode nullObject = ConstantNode.forObject(null, metaAccess, graph);
-                        piNode = graph.unique(new PiNode(nullObject, StampFactory.forConstant(nullObject.value, metaAccess), replacementAnchor.asNode()));
+                        piNode = graph.unique(new PiNode(nullObject, StampFactory.forConstant(nullObject.getValue(), metaAccess), replacementAnchor.asNode()));
                     } else {
                         piNode = graph.unique(new PiNode(object, StampFactory.declared(type, nonNull), replacementAnchor.asNode()));
                     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Sun Nov 03 15:27:52 2013 +0100
@@ -112,13 +112,17 @@
         for (Node node : graph.getNodes()) {
             if (flood.isMarked(node)) {
                 for (Node input : node.inputs()) {
-                    flood.add(input);
+                    if (!input.isExternal()) {
+                        flood.add(input);
+                    }
                 }
             }
         }
         for (Node current : flood) {
             for (Node input : current.inputs()) {
-                flood.add(input);
+                if (!input.isExternal()) {
+                    flood.add(input);
+                }
             }
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Sun Nov 03 15:27:52 2013 +0100
@@ -39,6 +39,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
+import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -487,7 +488,7 @@
             ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(Representation.ObjectHub), metaAccess, graph);
             LoadHubNode receiverHub = graph.unique(new LoadHubNode(nonNullReceiver, typeHub.kind(), null));
 
-            CompareNode typeCheck = CompareNode.createCompareNode(Condition.EQ, receiverHub, typeHub);
+            CompareNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub);
             FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
             assert invoke.predecessor() != null;
 
@@ -803,7 +804,7 @@
                 FixedNode lastSucc = successors[concretes.size()];
                 for (int i = concretes.size() - 1; i >= 0; --i) {
                     LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].kind()));
-                    CompareNode methodCheck = CompareNode.createCompareNode(Condition.EQ, method, constantMethods[i]);
+                    CompareNode methodCheck = CompareNode.createCompareNode(graph, Condition.EQ, method, constantMethods[i]);
                     IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i]));
                     method.setNext(ifNode);
                     lastSucc = method;
@@ -1433,7 +1434,12 @@
             if (returnNode.result() instanceof LocalNode) {
                 returnValue = localReplacement.replacement(returnNode.result());
             } else if (returnNode.result() != null) {
-                returnValue = duplicates.get(returnNode.result());
+                returnValue = returnNode.result();
+                if (!returnValue.isExternal()) {
+                    returnValue = duplicates.get(returnValue);
+                } else if (returnValue instanceof ValueNumberable) {
+                    returnValue = graph.uniqueWithoutAdd(returnValue);
+                }
             }
             invoke.asNode().replaceAtUsages(returnValue);
             Node returnDuplicate = duplicates.get(returnNode);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Sun Nov 03 15:27:52 2013 +0100
@@ -98,7 +98,7 @@
                 // Short cut creation of null check guard if the object is known to be non-null.
                 return null;
             }
-            StructuredGraph graph = object.graph();
+            StructuredGraph graph = guardedNode.asNode().graph();
             if (graph.getGuardsStage().ordinal() > GuardsStage.FLOATING_GUARDS.ordinal()) {
                 NullCheckNode nullCheck = graph.add(new NullCheckNode(object));
                 graph.addBeforeFixed((FixedNode) guardedNode, nullCheck);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Sun Nov 03 15:27:52 2013 +0100
@@ -364,7 +364,7 @@
                         // stop iterating: fixed nodes within the given set are traversal roots
                         // anyway, and all other
                         // fixed nodes are known to be outside.
-                    } else if (!aboveBound.isMarked(node)) {
+                    } else if (!node.isExternal() && !aboveBound.isMarked(node)) {
                         worklist.add(node);
                         aboveBound.mark(node);
                     }
@@ -377,7 +377,9 @@
             while (!worklist.isEmpty()) {
                 Node current = worklist.remove();
                 for (Node input : current.inputs()) {
-                    aboveClosure.apply(current, input);
+                    if (!input.isExternal()) {
+                        aboveClosure.apply(current, input);
+                    }
                 }
             }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Sun Nov 03 15:27:52 2013 +0100
@@ -672,6 +672,10 @@
      * Determines the earliest block in which the given node can be scheduled.
      */
     private Block earliestBlock(Node node) {
+        if (node.isExternal()) {
+            return cfg.getStartBlock();
+        }
+
         Block earliest = cfg.getNodeToBlock().get(node);
         if (earliest != null) {
             return earliest;
@@ -987,7 +991,7 @@
             for (Node input : state.inputs()) {
                 if (input instanceof VirtualState) {
                     addUnscheduledToLatestSorting(b, (VirtualState) input, sortedInstructions, visited, reads, beforeLastLocation);
-                } else {
+                } else if (!input.isExternal()) {
                     addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
                 }
             }
@@ -1004,8 +1008,9 @@
             if (input instanceof FrameState) {
                 assert state == null;
                 state = (FrameState) input;
-            } else {
+            } else if (!input.isExternal()) {
                 addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited, reads, beforeLastLocation);
+
             }
         }
         List<FloatingNode> inputs = phantomInputs.get(i);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java	Sun Nov 03 15:27:52 2013 +0100
@@ -72,7 +72,7 @@
         for (ObjectEqualsNode cn : graph.getNodes().filter(ObjectEqualsNode.class)) {
             if (!isEqualsMethod(graph)) {
                 // bail out if we compare an object of type klass with == or != (except null checks)
-                assert !(checkUsage(cn.x(), cn.y(), context.getMetaAccess()) && checkUsage(cn.y(), cn.x(), context.getMetaAccess())) : "Verifcation of " + klass.getName() +
+                assert !(checkUsage(cn.x(), cn.y(), context.getMetaAccess()) && checkUsage(cn.y(), cn.x(), context.getMetaAccess())) : "Verification of " + klass.getName() +
                                 " usage failed: Comparing " + cn.x() + " and " + cn.y() + " in " + graph.method() + " must use .equals() for object equality, not '==' or '!='";
             }
         }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Sun Nov 03 15:27:52 2013 +0100
@@ -137,8 +137,9 @@
         ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG();
         BlockMap<List<ScheduledNode>> blockToNodes = schedule == null ? null : schedule.getBlockToNodesMap();
         Block[] blocks = cfg == null ? null : cfg.getBlocks();
-        writeNodes(graph);
-        writeBlocks(blocks, blockToNodes);
+        Map<Node, Integer> externalNodes = new HashMap<>();
+        writeNodes(graph, externalNodes);
+        writeBlocks(blocks, blockToNodes, externalNodes);
     }
 
     private void flush() throws IOException {
@@ -388,7 +389,17 @@
     }
 
     @SuppressWarnings("deprecation")
-    private void writeNodes(Graph graph) throws IOException {
+    private static int getNodeId(Node node, Map<Node, Integer> externalNodes) {
+        if (!node.isExternal()) {
+            return node.getId();
+        } else {
+            Integer id = externalNodes.get(node);
+            assert id != null;
+            return id;
+        }
+    }
+
+    private void writeNodes(Graph graph, Map<Node, Integer> externalNodes) throws IOException {
         NodesToDoubles probabilities = null;
         if (PrintGraphProbabilities.getValue()) {
             try {
@@ -397,14 +408,26 @@
             }
         }
         Map<Object, Object> props = new HashMap<>();
-        writeInt(graph.getNodeCount());
+        int firstExternalNodeId = graph.getNodeCount() + graph.getDeletedNodeCount();
+        for (Node node : graph.getNodes()) {
+            for (Node input : node.inputs()) {
+                if (input.isExternal()) {
+                    if (!externalNodes.containsKey(input)) {
+                        externalNodes.put(input, externalNodes.size() + firstExternalNodeId);
+                    }
+                }
+            }
+        }
+
+        writeInt(graph.getNodeCount() + externalNodes.size());
+
         for (Node node : graph.getNodes()) {
             NodeClass nodeClass = node.getNodeClass();
             node.getDebugProperties(props);
             if (probabilities != null && node instanceof FixedNode && probabilities.contains((FixedNode) node)) {
                 props.put("probability", probabilities.get((FixedNode) node));
             }
-            writeInt(node.getId());
+            writeInt(getNodeId(node, externalNodes));
             writePoolObject(nodeClass);
             writeByte(node.predecessor() == null ? 0 : 1);
             // properties
@@ -415,20 +438,35 @@
                 writePropertyObject(entry.getValue());
             }
             // inputs
-            writeEdges(node, nodeClass.getFirstLevelInputPositions());
+            writeEdges(node, nodeClass.getFirstLevelInputPositions(), externalNodes);
             // successors
-            writeEdges(node, nodeClass.getFirstLevelSuccessorPositions());
+            writeEdges(node, nodeClass.getFirstLevelSuccessorPositions(), externalNodes);
 
             props.clear();
         }
+        for (Node node : externalNodes.keySet()) {
+            NodeClass nodeClass = node.getNodeClass();
+            node.getDebugProperties(props);
+            writeInt(getNodeId(node, externalNodes));
+            writePoolObject(nodeClass);
+            writeByte(0);
+            // properties
+            writeShort((char) props.size());
+            for (Entry<Object, Object> entry : props.entrySet()) {
+                String key = entry.getKey().toString();
+                writePoolObject(key);
+                writePropertyObject(entry.getValue());
+            }
+            props.clear();
+        }
     }
 
-    private void writeEdges(Node node, Collection<Position> positions) throws IOException {
+    private void writeEdges(Node node, Collection<Position> positions, Map<Node, Integer> externalNodes) throws IOException {
         NodeClass nodeClass = node.getNodeClass();
         for (Position pos : positions) {
             if (pos.subIndex == NodeClass.NOT_ITERABLE) {
                 Node edge = nodeClass.get(node, pos);
-                writeNodeRef(edge);
+                writeNodeRef(edge, externalNodes);
             } else {
                 NodeList<?> list = nodeClass.getNodeList(node, pos);
                 if (list == null) {
@@ -438,24 +476,22 @@
                     assert listSize == ((char) listSize);
                     writeShort((char) listSize);
                     for (Node edge : list) {
-                        writeNodeRef(edge);
+                        writeNodeRef(edge, externalNodes);
                     }
                 }
             }
         }
     }
 
-    @SuppressWarnings("deprecation")
-    private void writeNodeRef(Node edge) throws IOException {
+    private void writeNodeRef(Node edge, Map<Node, Integer> externalNodes) throws IOException {
         if (edge != null) {
-            writeInt(edge.getId());
+            writeInt(getNodeId(edge, externalNodes));
         } else {
             writeInt(-1);
         }
     }
 
-    @SuppressWarnings("deprecation")
-    private void writeBlocks(Block[] blocks, BlockMap<List<ScheduledNode>> blockToNodes) throws IOException {
+    private void writeBlocks(Block[] blocks, BlockMap<List<ScheduledNode>> blockToNodes, Map<Node, Integer> externalNodes) throws IOException {
         if (blocks != null) {
             writeInt(blocks.length);
             for (Block block : blocks) {
@@ -463,7 +499,7 @@
                 writeInt(block.getId());
                 writeInt(nodes.size());
                 for (Node node : nodes) {
-                    writeInt(node.getId());
+                    writeInt(getNodeId(node, externalNodes));
                 }
                 writeInt(block.getSuccessors().size());
                 for (Block sux : block.getSuccessors()) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Sun Nov 03 15:27:52 2013 +0100
@@ -141,7 +141,7 @@
             }
             if (condition == null || condition.y() != testValue) {
                 // Re-use previously generated condition if the trueValue for the test is the same
-                condition = createCompareNode(Condition.EQ, result, testValue);
+                condition = createCompareNode(result.graph(), Condition.EQ, result, testValue);
             }
             return condition;
         }
@@ -152,13 +152,13 @@
          * @param t the true value for the materialization
          * @param f the false value for the materialization
          */
-        ValueNode asMaterialization(ValueNode t, ValueNode f) {
+        ValueNode asMaterialization(StructuredGraph graph, ValueNode t, ValueNode f) {
             assert isInitialized();
             if (t == this.trueValue && f == this.falseValue) {
                 // Can simply use the phi result if the same materialized values are expected.
                 return result;
             } else {
-                return t.graph().unique(new ConditionalNode(asCondition(trueValue), t, f));
+                return graph.unique(new ConditionalNode(asCondition(trueValue), t, f));
             }
         }
     }
@@ -230,7 +230,7 @@
 
         @Override
         public void replaceUsingInstantiation() {
-            ValueNode newValue = instantiation.asMaterialization(trueValue, falseValue);
+            ValueNode newValue = instantiation.asMaterialization(usage.graph(), trueValue, falseValue);
             usage.replaceAtUsages(newValue);
             usage.clearInputs();
             assert usage.usages().isEmpty();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Sun Nov 03 15:27:52 2013 +0100
@@ -72,6 +72,7 @@
         ResolvedJavaMethod target = methodCallTargetNode.targetMethod();
         NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class);
         ResolvedJavaType declaringClass = target.getDeclaringClass();
+        StructuredGraph graph = methodCallTargetNode.graph();
         if (intrinsic != null) {
             assert target.getAnnotation(Fold.class) == null;
             assert Modifier.isStatic(target.getModifiers()) : "node intrinsic must be static: " + target;
@@ -86,10 +87,10 @@
 
             // Create the new node instance.
             ResolvedJavaType c = getNodeClass(target, intrinsic);
-            Node newInstance = createNodeInstance(c, parameterTypes, methodCallTargetNode.invoke().asNode().stamp(), intrinsic.setStampFromReturnType(), nodeConstructorArguments);
+            Node newInstance = createNodeInstance(graph, c, parameterTypes, methodCallTargetNode.invoke().asNode().stamp(), intrinsic.setStampFromReturnType(), nodeConstructorArguments);
 
             // Replace the invoke with the new node.
-            newInstance = methodCallTargetNode.graph().addOrUnique(newInstance);
+            newInstance = graph.addOrUnique(newInstance);
             methodCallTargetNode.invoke().intrinsify(newInstance);
 
             // Clean up checkcast instructions inserted by javac if the return type is generic.
@@ -194,12 +195,13 @@
         return result;
     }
 
-    private Node createNodeInstance(ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, Stamp invokeStamp, boolean setStampFromReturnType, Constant[] nodeConstructorArguments) {
+    private Node createNodeInstance(StructuredGraph graph, ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, Stamp invokeStamp, boolean setStampFromReturnType,
+                    Constant[] nodeConstructorArguments) {
         ResolvedJavaMethod constructor = null;
         Constant[] arguments = null;
 
         for (ResolvedJavaMethod c : nodeClass.getDeclaredConstructors()) {
-            Constant[] match = match(c, parameterTypes, nodeConstructorArguments);
+            Constant[] match = match(graph, c, parameterTypes, nodeConstructorArguments);
 
             if (match != null) {
                 if (constructor == null) {
@@ -246,7 +248,7 @@
         return false;
     }
 
-    private Constant[] match(ResolvedJavaMethod c, ResolvedJavaType[] parameterTypes, Constant[] nodeConstructorArguments) {
+    private Constant[] match(StructuredGraph graph, ResolvedJavaMethod c, ResolvedJavaType[] parameterTypes, Constant[] nodeConstructorArguments) {
         Constant[] arguments = null;
         Constant[] injected = null;
 
@@ -257,6 +259,8 @@
                 injected = injected == null ? new Constant[1] : Arrays.copyOf(injected, injected.length + 1);
                 if (signature[i].equals(metaAccess.lookupJavaType(MetaAccessProvider.class))) {
                     injected[injected.length - 1] = Constant.forObject(metaAccess);
+                } else if (signature[i].equals(metaAccess.lookupJavaType(StructuredGraph.class))) {
+                    injected[injected.length - 1] = Constant.forObject(graph);
                 } else if (signature[i].equals(metaAccess.lookupJavaType(ForeignCallsProvider.class))) {
                     injected[injected.length - 1] = Constant.forObject(providers.getForeignCalls());
                 } else {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -61,10 +61,9 @@
             } else {
                 locationIdentity = ObjectLocationIdentity.create(locationIdentityObject);
             }
-            Node result = graph().add(
-                            new UnsafeLoadNode(objectArgument, offsetArgument, this.getTargetMethod().getSignature().getReturnKind(), locationIdentity, CompareNode.createCompareNode(Condition.EQ,
-                                            conditionArgument, ConstantNode.forBoolean(true, graph()))));
-
+            CompareNode compare = CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()));
+            Kind returnKind = this.getTargetMethod().getSignature().getReturnKind();
+            Node result = graph().add(new UnsafeLoadNode(objectArgument, offsetArgument, returnKind, locationIdentity, compare));
             return result;
         }
         return this;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Sun Nov 03 15:27:52 2013 +0100
@@ -58,7 +58,7 @@
                 return objectArgument;
             }
             ResolvedJavaType lookupJavaType = tool.getMetaAccess().lookupJavaType(c);
-            ConditionAnchorNode valueAnchorNode = graph().add(new ConditionAnchorNode(CompareNode.createCompareNode(Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()))));
+            ConditionAnchorNode valueAnchorNode = graph().add(new ConditionAnchorNode(CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()))));
             UnsafeCastNode piCast = graph().unique(new UnsafeCastNode(objectArgument, StampFactory.declaredNonNull(lookupJavaType), valueAnchorNode));
             this.replaceAtUsages(piCast);
             return valueAnchorNode;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Sun Nov 03 15:27:52 2013 +0100
@@ -231,7 +231,7 @@
 
     public ValueNode getScalarAlias(ValueNode node) {
         assert !(node instanceof VirtualObjectNode);
-        if (node == null || !node.isAlive() || aliases.isNew(node)) {
+        if (node == null || !node.isAlive() || node.isExternal() || aliases.isNew(node)) {
             return node;
         }
         ValueNode result = aliases.get(node);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Sun Nov 03 15:27:52 2013 +0100
@@ -616,7 +616,7 @@
     }
 
     public ObjectState getObjectState(PartialEscapeBlockState<?> state, ValueNode value) {
-        if (value == null) {
+        if (value == null || value.isExternal()) {
             return null;
         }
         if (value.isAlive() && !aliases.isNew(value)) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Sun Nov 03 15:27:52 2013 +0100
@@ -69,18 +69,22 @@
         for (Node node : graph.getNodes()) {
             if (flood.isMarked(node)) {
                 for (Node input : node.inputs()) {
-                    flood.add(input);
-                    if (!path.containsKey(input)) {
-                        path.put(input, node);
+                    if (!input.isExternal()) {
+                        flood.add(input);
+                        if (!path.containsKey(input)) {
+                            path.put(input, node);
+                        }
                     }
                 }
             }
         }
         for (Node current : flood) {
             for (Node input : current.inputs()) {
-                flood.add(input);
-                if (!path.containsKey(input)) {
-                    path.put(input, current);
+                if (!input.isExternal()) {
+                    flood.add(input);
+                    if (!path.containsKey(input)) {
+                        path.put(input, current);
+                    }
                 }
             }
         }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Fri Nov 01 19:35:33 2013 -0700
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Sun Nov 03 15:27:52 2013 +0100
@@ -114,8 +114,8 @@
         if (isWord(node)) {
             if (node.isConstant()) {
                 ConstantNode oldConstant = (ConstantNode) node;
-                assert oldConstant.value.getKind() == Kind.Object;
-                WordBase value = (WordBase) oldConstant.value.asObject();
+                assert oldConstant.getValue().getKind() == Kind.Object;
+                WordBase value = (WordBase) oldConstant.getValue().asObject();
                 ConstantNode newConstant = ConstantNode.forIntegerKind(wordKind, value.rawValue(), node.graph());
                 graph.replaceFloating(oldConstant, newConstant);